summaryrefslogtreecommitdiffstats
path: root/scripts/lib/mic/utils/misc.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/mic/utils/misc.py')
-rw-r--r--scripts/lib/mic/utils/misc.py1067
1 files changed, 1067 insertions, 0 deletions
diff --git a/scripts/lib/mic/utils/misc.py b/scripts/lib/mic/utils/misc.py
new file mode 100644
index 0000000000..63024346a9
--- /dev/null
+++ b/scripts/lib/mic/utils/misc.py
@@ -0,0 +1,1067 @@
1#!/usr/bin/python -tt
2#
3# Copyright (c) 2010, 2011 Intel Inc.
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by the Free
7# Software Foundation; version 2 of the License
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12# for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc., 59
16# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18import os
19import sys
20import time
21import tempfile
22import re
23import shutil
24import glob
25import hashlib
26import subprocess
27import platform
28import traceback
29
30
31try:
32 import sqlite3 as sqlite
33except ImportError:
34 import sqlite
35
36try:
37 from xml.etree import cElementTree
38except ImportError:
39 import cElementTree
40xmlparse = cElementTree.parse
41
42from mic import msger
43from mic.utils.errors import CreatorError, SquashfsError
44from mic.utils.fs_related import find_binary_path, makedirs
45from mic.utils.grabber import myurlgrab
46from mic.utils.proxy import get_proxy_for
47from mic.utils import runner
48from mic.utils import rpmmisc
49
50
51RPM_RE = re.compile("(.*)\.(.*) (.*)-(.*)")
52RPM_FMT = "%(name)s.%(arch)s %(version)s-%(release)s"
53SRPM_RE = re.compile("(.*)-(\d+.*)-(\d+\.\d+).src.rpm")
54
55
56def build_name(kscfg, release=None, prefix = None, suffix = None):
57 """Construct and return an image name string.
58
59 This is a utility function to help create sensible name and fslabel
60 strings. The name is constructed using the sans-prefix-and-extension
61 kickstart filename and the supplied prefix and suffix.
62
63 kscfg -- a path to a kickstart file
64 release -- a replacement to suffix for image release
65 prefix -- a prefix to prepend to the name; defaults to None, which causes
66 no prefix to be used
67 suffix -- a suffix to append to the name; defaults to None, which causes
68 a YYYYMMDDHHMM suffix to be used
69
70 Note, if maxlen is less then the len(suffix), you get to keep both pieces.
71
72 """
73 name = os.path.basename(kscfg)
74 idx = name.rfind('.')
75 if idx >= 0:
76 name = name[:idx]
77
78 if release is not None:
79 suffix = ""
80 if prefix is None:
81 prefix = ""
82 if suffix is None:
83 suffix = time.strftime("%Y%m%d%H%M")
84
85 if name.startswith(prefix):
86 name = name[len(prefix):]
87
88 prefix = "%s-" % prefix if prefix else ""
89 suffix = "-%s" % suffix if suffix else ""
90
91 ret = prefix + name + suffix
92 return ret
93
94def get_distro():
95 """Detect linux distribution, support "meego"
96 """
97
98 support_dists = ('SuSE',
99 'debian',
100 'fedora',
101 'redhat',
102 'centos',
103 'meego',
104 'moblin',
105 'tizen')
106 try:
107 (dist, ver, id) = platform.linux_distribution( \
108 supported_dists = support_dists)
109 except:
110 (dist, ver, id) = platform.dist( \
111 supported_dists = support_dists)
112
113 return (dist, ver, id)
114
115def get_distro_str():
116 """Get composited string for current linux distribution
117 """
118 (dist, ver, id) = get_distro()
119
120 if not dist:
121 return 'Unknown Linux Distro'
122 else:
123 distro_str = ' '.join(map(str.strip, (dist, ver, id)))
124 return distro_str.strip()
125
126_LOOP_RULE_PTH = None
127
128def hide_loopdev_presentation():
129 udev_rules = "80-prevent-loop-present.rules"
130 udev_rules_dir = [
131 '/usr/lib/udev/rules.d/',
132 '/lib/udev/rules.d/',
133 '/etc/udev/rules.d/'
134 ]
135
136 global _LOOP_RULE_PTH
137
138 for rdir in udev_rules_dir:
139 if os.path.exists(rdir):
140 _LOOP_RULE_PTH = os.path.join(rdir, udev_rules)
141
142 if not _LOOP_RULE_PTH:
143 return
144
145 try:
146 with open(_LOOP_RULE_PTH, 'w') as wf:
147 wf.write('KERNEL=="loop*", ENV{UDISKS_PRESENTATION_HIDE}="1"')
148
149 runner.quiet('udevadm trigger')
150 except:
151 pass
152
153def unhide_loopdev_presentation():
154 global _LOOP_RULE_PTH
155
156 if not _LOOP_RULE_PTH:
157 return
158
159 try:
160 os.unlink(_LOOP_RULE_PTH)
161 runner.quiet('udevadm trigger')
162 except:
163 pass
164
165def extract_rpm(rpmfile, targetdir):
166 rpm2cpio = find_binary_path("rpm2cpio")
167 cpio = find_binary_path("cpio")
168
169 olddir = os.getcwd()
170 os.chdir(targetdir)
171
172 msger.verbose("Extract rpm file with cpio: %s" % rpmfile)
173 p1 = subprocess.Popen([rpm2cpio, rpmfile], stdout=subprocess.PIPE)
174 p2 = subprocess.Popen([cpio, "-idv"], stdin=p1.stdout,
175 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
176 (sout, serr) = p2.communicate()
177 msger.verbose(sout or serr)
178
179 os.chdir(olddir)
180
181def compressing(fpath, method):
182 comp_map = {
183 "gz": "gzip",
184 "bz2": "bzip2"
185 }
186 if method not in comp_map:
187 raise CreatorError("Unsupport compress format: %s, valid values: %s"
188 % (method, ','.join(comp_map.keys())))
189 cmd = find_binary_path(comp_map[method])
190 rc = runner.show([cmd, "-f", fpath])
191 if rc:
192 raise CreatorError("Failed to %s file: %s" % (comp_map[method], fpath))
193
194def taring(dstfile, target):
195 import tarfile
196 basen, ext = os.path.splitext(dstfile)
197 comp = {".tar": None,
198 ".gz": "gz", # for .tar.gz
199 ".bz2": "bz2", # for .tar.bz2
200 ".tgz": "gz",
201 ".tbz": "bz2"}[ext]
202
203 # specify tarball file path
204 if not comp:
205 tarpath = dstfile
206 elif basen.endswith(".tar"):
207 tarpath = basen
208 else:
209 tarpath = basen + ".tar"
210 wf = tarfile.open(tarpath, 'w')
211
212 if os.path.isdir(target):
213 for item in os.listdir(target):
214 wf.add(os.path.join(target, item), item)
215 else:
216 wf.add(target, os.path.basename(target))
217 wf.close()
218
219 if comp:
220 compressing(tarpath, comp)
221 # when dstfile ext is ".tgz" and ".tbz", should rename
222 if not basen.endswith(".tar"):
223 shutil.move("%s.%s" % (tarpath, comp), dstfile)
224
225def ziping(dstfile, target):
226 import zipfile
227 wf = zipfile.ZipFile(dstfile, 'w', compression=zipfile.ZIP_DEFLATED)
228 if os.path.isdir(target):
229 for item in os.listdir(target):
230 fpath = os.path.join(target, item)
231 if not os.path.isfile(fpath):
232 continue
233 wf.write(fpath, item, zipfile.ZIP_DEFLATED)
234 else:
235 wf.write(target, os.path.basename(target), zipfile.ZIP_DEFLATED)
236 wf.close()
237
238pack_formats = {
239 ".tar": taring,
240 ".tar.gz": taring,
241 ".tar.bz2": taring,
242 ".tgz": taring,
243 ".tbz": taring,
244 ".zip": ziping,
245}
246
247def packing(dstfile, target):
248 (base, ext) = os.path.splitext(dstfile)
249 if ext in (".gz", ".bz2") and base.endswith(".tar"):
250 ext = ".tar" + ext
251 if ext not in pack_formats:
252 raise CreatorError("Unsupport pack format: %s, valid values: %s"
253 % (ext, ','.join(pack_formats.keys())))
254 func = pack_formats[ext]
255 # func should be callable
256 func(dstfile, target)
257
258def human_size(size):
259 """Return human readable string for Bytes size
260 """
261
262 if size <= 0:
263 return "0M"
264 import math
265 measure = ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
266 expo = int(math.log(size, 1024))
267 mant = float(size/math.pow(1024, expo))
268 return "{0:.1f}{1:s}".format(mant, measure[expo])
269
270def get_block_size(file_obj):
271 """ Returns block size for file object 'file_obj'. Errors are indicated by
272 the 'IOError' exception. """
273
274 from fcntl import ioctl
275 import struct
276
277 # Get the block size of the host file-system for the image file by calling
278 # the FIGETBSZ ioctl (number 2).
279 binary_data = ioctl(file_obj, 2, struct.pack('I', 0))
280 return struct.unpack('I', binary_data)[0]
281
282def check_space_pre_cp(src, dst):
283 """Check whether disk space is enough before 'cp' like
284 operations, else exception will be raised.
285 """
286
287 srcsize = get_file_size(src) * 1024 * 1024
288 freesize = get_filesystem_avail(dst)
289 if srcsize > freesize:
290 raise CreatorError("space on %s(%s) is not enough for about %s files"
291 % (dst, human_size(freesize), human_size(srcsize)))
292
293def calc_hashes(file_path, hash_names, start = 0, end = None):
294 """ Calculate hashes for a file. The 'file_path' argument is the file
295 to calculate hash functions for, 'start' and 'end' are the starting and
296 ending file offset to calculate the has functions for. The 'hash_names'
297 argument is a list of hash names to calculate. Returns the the list
298 of calculated hash values in the hexadecimal form in the same order
299 as 'hash_names'.
300 """
301 if end == None:
302 end = os.path.getsize(file_path)
303
304 chunk_size = 65536
305 to_read = end - start
306 read = 0
307
308 hashes = []
309 for hash_name in hash_names:
310 hashes.append(hashlib.new(hash_name))
311
312 with open(file_path, "rb") as f:
313 f.seek(start)
314
315 while read < to_read:
316 if read + chunk_size > to_read:
317 chunk_size = to_read - read
318 chunk = f.read(chunk_size)
319 for hash_obj in hashes:
320 hash_obj.update(chunk)
321 read += chunk_size
322
323 result = []
324 for hash_obj in hashes:
325 result.append(hash_obj.hexdigest())
326
327 return result
328
329def get_md5sum(fpath):
330 return calc_hashes(fpath, ('md5', ))[0]
331
332
333def normalize_ksfile(ksconf, release, arch):
334 '''
335 Return the name of a normalized ks file in which macro variables
336 @BUILD_ID@ and @ARCH@ are replace with real values.
337
338 The original ks file is returned if no special macro is used, otherwise
339 a temp file is created and returned, which will be deleted when program
340 exits normally.
341 '''
342
343 if not release:
344 release = "latest"
345 if not arch or re.match(r'i.86', arch):
346 arch = "ia32"
347
348 with open(ksconf) as f:
349 ksc = f.read()
350
351 if "@ARCH@" not in ksc and "@BUILD_ID@" not in ksc:
352 return ksconf
353
354 msger.info("Substitute macro variable @BUILD_ID@/@ARCH@ in ks: %s" % ksconf)
355 ksc = ksc.replace("@ARCH@", arch)
356 ksc = ksc.replace("@BUILD_ID@", release)
357
358 fd, ksconf = tempfile.mkstemp(prefix=os.path.basename(ksconf))
359 os.write(fd, ksc)
360 os.close(fd)
361
362 msger.debug('normalized ks file:%s' % ksconf)
363
364 def remove_temp_ks():
365 try:
366 os.unlink(ksconf)
367 except OSError, err:
368 msger.warning('Failed to remove temp ks file:%s:%s' % (ksconf, err))
369
370 import atexit
371 atexit.register(remove_temp_ks)
372
373 return ksconf
374
375
376def _check_mic_chroot(rootdir):
377 def _path(path):
378 return rootdir.rstrip('/') + path
379
380 release_files = map(_path, [ "/etc/moblin-release",
381 "/etc/meego-release",
382 "/etc/tizen-release"])
383
384 if not any(map(os.path.exists, release_files)):
385 msger.warning("Dir %s is not a MeeGo/Tizen chroot env" % rootdir)
386
387 if not glob.glob(rootdir + "/boot/vmlinuz-*"):
388 msger.warning("Failed to find kernel module under %s" % rootdir)
389
390 return
391
392def selinux_check(arch, fstypes):
393 try:
394 getenforce = find_binary_path('getenforce')
395 except CreatorError:
396 return
397
398 selinux_status = runner.outs([getenforce])
399 if arch and arch.startswith("arm") and selinux_status == "Enforcing":
400 raise CreatorError("Can't create arm image if selinux is enabled, "
401 "please run 'setenforce 0' to disable selinux")
402
403 use_btrfs = filter(lambda typ: typ == 'btrfs', fstypes)
404 if use_btrfs and selinux_status == "Enforcing":
405 raise CreatorError("Can't create btrfs image if selinux is enabled,"
406 " please run 'setenforce 0' to disable selinux")
407
408def get_image_type(path):
409 def _get_extension_name(path):
410 match = re.search("(?<=\.)\w+$", path)
411 if match:
412 return match.group(0)
413 else:
414 return None
415
416 if os.path.isdir(path):
417 _check_mic_chroot(path)
418 return "fs"
419
420 maptab = {
421 "tar": "loop",
422 "raw":"raw",
423 "vmdk":"vmdk",
424 "vdi":"vdi",
425 "iso":"livecd",
426 "usbimg":"liveusb",
427 }
428
429 extension = _get_extension_name(path)
430 if extension in maptab:
431 return maptab[extension]
432
433 fd = open(path, "rb")
434 file_header = fd.read(1024)
435 fd.close()
436 vdi_flag = "<<< Sun VirtualBox Disk Image >>>"
437 if file_header[0:len(vdi_flag)] == vdi_flag:
438 return maptab["vdi"]
439
440 output = runner.outs(['file', path])
441 isoptn = re.compile(r".*ISO 9660 CD-ROM filesystem.*(bootable).*")
442 usbimgptn = re.compile(r".*x86 boot sector.*active.*")
443 rawptn = re.compile(r".*x86 boot sector.*")
444 vmdkptn = re.compile(r".*VMware. disk image.*")
445 ext3fsimgptn = re.compile(r".*Linux.*ext3 filesystem data.*")
446 ext4fsimgptn = re.compile(r".*Linux.*ext4 filesystem data.*")
447 btrfsimgptn = re.compile(r".*BTRFS.*")
448 if isoptn.match(output):
449 return maptab["iso"]
450 elif usbimgptn.match(output):
451 return maptab["usbimg"]
452 elif rawptn.match(output):
453 return maptab["raw"]
454 elif vmdkptn.match(output):
455 return maptab["vmdk"]
456 elif ext3fsimgptn.match(output):
457 return "ext3fsimg"
458 elif ext4fsimgptn.match(output):
459 return "ext4fsimg"
460 elif btrfsimgptn.match(output):
461 return "btrfsimg"
462 else:
463 raise CreatorError("Cannot detect the type of image: %s" % path)
464
465
466def get_file_size(filename):
467 """ Return size in MB unit """
468 cmd = ['du', "-s", "-b", "-B", "1M", filename]
469 rc, duOutput = runner.runtool(cmd)
470 if rc != 0:
471 raise CreatorError("Failed to run: %s" % ' '.join(cmd))
472 size1 = int(duOutput.split()[0])
473
474 cmd = ['du', "-s", "-B", "1M", filename]
475 rc, duOutput = runner.runtool(cmd)
476 if rc != 0:
477 raise CreatorError("Failed to run: %s" % ' '.join(cmd))
478
479 size2 = int(duOutput.split()[0])
480 return max(size1, size2)
481
482
483def get_filesystem_avail(fs):
484 vfstat = os.statvfs(fs)
485 return vfstat.f_bavail * vfstat.f_bsize
486
487def convert_image(srcimg, srcfmt, dstimg, dstfmt):
488 #convert disk format
489 if dstfmt != "raw":
490 raise CreatorError("Invalid destination image format: %s" % dstfmt)
491 msger.debug("converting %s image to %s" % (srcimg, dstimg))
492 if srcfmt == "vmdk":
493 path = find_binary_path("qemu-img")
494 argv = [path, "convert", "-f", "vmdk", srcimg, "-O", dstfmt, dstimg]
495 elif srcfmt == "vdi":
496 path = find_binary_path("VBoxManage")
497 argv = [path, "internalcommands", "converttoraw", srcimg, dstimg]
498 else:
499 raise CreatorError("Invalid soure image format: %s" % srcfmt)
500
501 rc = runner.show(argv)
502 if rc == 0:
503 msger.debug("convert successful")
504 if rc != 0:
505 raise CreatorError("Unable to convert disk to %s" % dstfmt)
506
507def uncompress_squashfs(squashfsimg, outdir):
508 """Uncompress file system from squshfs image"""
509 unsquashfs = find_binary_path("unsquashfs")
510 args = [ unsquashfs, "-d", outdir, squashfsimg ]
511 rc = runner.show(args)
512 if (rc != 0):
513 raise SquashfsError("Failed to uncompress %s." % squashfsimg)
514
515def mkdtemp(dir = "/var/tmp", prefix = "mic-tmp-"):
516 """ FIXME: use the dir in mic.conf instead """
517
518 makedirs(dir)
519 return tempfile.mkdtemp(dir = dir, prefix = prefix)
520
521def get_repostrs_from_ks(ks):
522 def _get_temp_reponame(baseurl):
523 md5obj = hashlib.md5(baseurl)
524 tmpreponame = "%s" % md5obj.hexdigest()
525 return tmpreponame
526
527 kickstart_repos = []
528
529 for repodata in ks.handler.repo.repoList:
530 repo = {}
531 for attr in ('name',
532 'baseurl',
533 'mirrorlist',
534 'includepkgs', # val is list
535 'excludepkgs', # val is list
536 'cost', # int
537 'priority',# int
538 'save',
539 'proxy',
540 'proxyuser',
541 'proxypasswd',
542 'proxypasswd',
543 'debuginfo',
544 'source',
545 'gpgkey',
546 'ssl_verify'):
547 if hasattr(repodata, attr) and getattr(repodata, attr):
548 repo[attr] = getattr(repodata, attr)
549
550 if 'name' not in repo:
551 repo['name'] = _get_temp_reponame(repodata.baseurl)
552
553 kickstart_repos.append(repo)
554
555 return kickstart_repos
556
557def _get_uncompressed_data_from_url(url, filename, proxies):
558 filename = myurlgrab(url, filename, proxies)
559 suffix = None
560 if filename.endswith(".gz"):
561 suffix = ".gz"
562 runner.quiet(['gunzip', "-f", filename])
563 elif filename.endswith(".bz2"):
564 suffix = ".bz2"
565 runner.quiet(['bunzip2', "-f", filename])
566 if suffix:
567 filename = filename.replace(suffix, "")
568 return filename
569
570def _get_metadata_from_repo(baseurl, proxies, cachedir, reponame, filename,
571 sumtype=None, checksum=None):
572 url = os.path.join(baseurl, filename)
573 filename_tmp = str("%s/%s/%s" % (cachedir, reponame, os.path.basename(filename)))
574 if os.path.splitext(filename_tmp)[1] in (".gz", ".bz2"):
575 filename = os.path.splitext(filename_tmp)[0]
576 else:
577 filename = filename_tmp
578 if sumtype and checksum and os.path.exists(filename):
579 try:
580 sumcmd = find_binary_path("%ssum" % sumtype)
581 except:
582 file_checksum = None
583 else:
584 file_checksum = runner.outs([sumcmd, filename]).split()[0]
585
586 if file_checksum and file_checksum == checksum:
587 return filename
588
589 return _get_uncompressed_data_from_url(url,filename_tmp,proxies)
590
591def get_metadata_from_repos(repos, cachedir):
592 my_repo_metadata = []
593 for repo in repos:
594 reponame = repo['name']
595 baseurl = repo['baseurl']
596
597
598 if 'proxy' in repo:
599 proxy = repo['proxy']
600 else:
601 proxy = get_proxy_for(baseurl)
602
603 proxies = None
604 if proxy:
605 proxies = {str(baseurl.split(":")[0]):str(proxy)}
606
607 makedirs(os.path.join(cachedir, reponame))
608 url = os.path.join(baseurl, "repodata/repomd.xml")
609 filename = os.path.join(cachedir, reponame, 'repomd.xml')
610 repomd = myurlgrab(url, filename, proxies)
611 try:
612 root = xmlparse(repomd)
613 except SyntaxError:
614 raise CreatorError("repomd.xml syntax error.")
615
616 ns = root.getroot().tag
617 ns = ns[0:ns.rindex("}")+1]
618
619 filepaths = {}
620 checksums = {}
621 sumtypes = {}
622
623 for elm in root.getiterator("%sdata" % ns):
624 if elm.attrib["type"] == "patterns":
625 filepaths['patterns'] = elm.find("%slocation" % ns).attrib['href']
626 checksums['patterns'] = elm.find("%sopen-checksum" % ns).text
627 sumtypes['patterns'] = elm.find("%sopen-checksum" % ns).attrib['type']
628 break
629
630 for elm in root.getiterator("%sdata" % ns):
631 if elm.attrib["type"] in ("group_gz", "group"):
632 filepaths['comps'] = elm.find("%slocation" % ns).attrib['href']
633 checksums['comps'] = elm.find("%sopen-checksum" % ns).text
634 sumtypes['comps'] = elm.find("%sopen-checksum" % ns).attrib['type']
635 break
636
637 primary_type = None
638 for elm in root.getiterator("%sdata" % ns):
639 if elm.attrib["type"] in ("primary_db", "primary"):
640 primary_type = elm.attrib["type"]
641 filepaths['primary'] = elm.find("%slocation" % ns).attrib['href']
642 checksums['primary'] = elm.find("%sopen-checksum" % ns).text
643 sumtypes['primary'] = elm.find("%sopen-checksum" % ns).attrib['type']
644 break
645
646 if not primary_type:
647 continue
648
649 for item in ("primary", "patterns", "comps"):
650 if item not in filepaths:
651 filepaths[item] = None
652 continue
653 if not filepaths[item]:
654 continue
655 filepaths[item] = _get_metadata_from_repo(baseurl,
656 proxies,
657 cachedir,
658 reponame,
659 filepaths[item],
660 sumtypes[item],
661 checksums[item])
662
663 """ Get repo key """
664 try:
665 repokey = _get_metadata_from_repo(baseurl,
666 proxies,
667 cachedir,
668 reponame,
669 "repodata/repomd.xml.key")
670 except CreatorError:
671 repokey = None
672 msger.debug("\ncan't get %s/%s" % (baseurl, "repodata/repomd.xml.key"))
673
674 my_repo_metadata.append({"name":reponame,
675 "baseurl":baseurl,
676 "repomd":repomd,
677 "primary":filepaths['primary'],
678 "cachedir":cachedir,
679 "proxies":proxies,
680 "patterns":filepaths['patterns'],
681 "comps":filepaths['comps'],
682 "repokey":repokey})
683
684 return my_repo_metadata
685
686def get_rpmver_in_repo(repometadata):
687 for repo in repometadata:
688 if repo["primary"].endswith(".xml"):
689 root = xmlparse(repo["primary"])
690 ns = root.getroot().tag
691 ns = ns[0:ns.rindex("}")+1]
692
693 versionlist = []
694 for elm in root.getiterator("%spackage" % ns):
695 if elm.find("%sname" % ns).text == 'rpm':
696 for node in elm.getchildren():
697 if node.tag == "%sversion" % ns:
698 versionlist.append(node.attrib['ver'])
699
700 if versionlist:
701 return reversed(
702 sorted(
703 versionlist,
704 key = lambda ver: map(int, ver.split('.')))).next()
705
706 elif repo["primary"].endswith(".sqlite"):
707 con = sqlite.connect(repo["primary"])
708 for row in con.execute("select version from packages where "
709 "name=\"rpm\" ORDER by version DESC"):
710 con.close()
711 return row[0]
712
713 return None
714
715def get_arch(repometadata):
716 archlist = []
717 for repo in repometadata:
718 if repo["primary"].endswith(".xml"):
719 root = xmlparse(repo["primary"])
720 ns = root.getroot().tag
721 ns = ns[0:ns.rindex("}")+1]
722 for elm in root.getiterator("%spackage" % ns):
723 if elm.find("%sarch" % ns).text not in ("noarch", "src"):
724 arch = elm.find("%sarch" % ns).text
725 if arch not in archlist:
726 archlist.append(arch)
727 elif repo["primary"].endswith(".sqlite"):
728 con = sqlite.connect(repo["primary"])
729 for row in con.execute("select arch from packages where arch not in (\"src\", \"noarch\")"):
730 if row[0] not in archlist:
731 archlist.append(row[0])
732
733 con.close()
734
735 uniq_arch = []
736 for i in range(len(archlist)):
737 if archlist[i] not in rpmmisc.archPolicies.keys():
738 continue
739 need_append = True
740 j = 0
741 while j < len(uniq_arch):
742 if archlist[i] in rpmmisc.archPolicies[uniq_arch[j]].split(':'):
743 need_append = False
744 break
745 if uniq_arch[j] in rpmmisc.archPolicies[archlist[i]].split(':'):
746 if need_append:
747 uniq_arch[j] = archlist[i]
748 need_append = False
749 else:
750 uniq_arch.remove(uniq_arch[j])
751 continue
752 j += 1
753 if need_append:
754 uniq_arch.append(archlist[i])
755
756 return uniq_arch, archlist
757
758def get_package(pkg, repometadata, arch = None):
759 ver = ""
760 target_repo = None
761 if not arch:
762 arches = []
763 elif arch not in rpmmisc.archPolicies:
764 arches = [arch]
765 else:
766 arches = rpmmisc.archPolicies[arch].split(':')
767 arches.append('noarch')
768
769 for repo in repometadata:
770 if repo["primary"].endswith(".xml"):
771 root = xmlparse(repo["primary"])
772 ns = root.getroot().tag
773 ns = ns[0:ns.rindex("}")+1]
774 for elm in root.getiterator("%spackage" % ns):
775 if elm.find("%sname" % ns).text == pkg:
776 if elm.find("%sarch" % ns).text in arches:
777 version = elm.find("%sversion" % ns)
778 tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
779 if tmpver > ver:
780 ver = tmpver
781 location = elm.find("%slocation" % ns)
782 pkgpath = "%s" % location.attrib['href']
783 target_repo = repo
784 break
785 if repo["primary"].endswith(".sqlite"):
786 con = sqlite.connect(repo["primary"])
787 if arch:
788 sql = 'select version, release, location_href from packages ' \
789 'where name = "%s" and arch IN ("%s")' % \
790 (pkg, '","'.join(arches))
791 for row in con.execute(sql):
792 tmpver = "%s-%s" % (row[0], row[1])
793 if tmpver > ver:
794 ver = tmpver
795 pkgpath = "%s" % row[2]
796 target_repo = repo
797 break
798 else:
799 sql = 'select version, release, location_href from packages ' \
800 'where name = "%s"' % pkg
801 for row in con.execute(sql):
802 tmpver = "%s-%s" % (row[0], row[1])
803 if tmpver > ver:
804 ver = tmpver
805 pkgpath = "%s" % row[2]
806 target_repo = repo
807 break
808 con.close()
809 if target_repo:
810 makedirs("%s/packages/%s" % (target_repo["cachedir"], target_repo["name"]))
811 url = os.path.join(target_repo["baseurl"], pkgpath)
812 filename = str("%s/packages/%s/%s" % (target_repo["cachedir"], target_repo["name"], os.path.basename(pkgpath)))
813 if os.path.exists(filename):
814 ret = rpmmisc.checkRpmIntegrity('rpm', filename)
815 if ret == 0:
816 return filename
817
818 msger.warning("package %s is damaged: %s" %
819 (os.path.basename(filename), filename))
820 os.unlink(filename)
821
822 pkg = myurlgrab(str(url), filename, target_repo["proxies"])
823 return pkg
824 else:
825 return None
826
827def get_source_name(pkg, repometadata):
828
829 def get_bin_name(pkg):
830 m = RPM_RE.match(pkg)
831 if m:
832 return m.group(1)
833 return None
834
835 def get_src_name(srpm):
836 m = SRPM_RE.match(srpm)
837 if m:
838 return m.group(1)
839 return None
840
841 ver = ""
842 target_repo = None
843
844 pkg_name = get_bin_name(pkg)
845 if not pkg_name:
846 return None
847
848 for repo in repometadata:
849 if repo["primary"].endswith(".xml"):
850 root = xmlparse(repo["primary"])
851 ns = root.getroot().tag
852 ns = ns[0:ns.rindex("}")+1]
853 for elm in root.getiterator("%spackage" % ns):
854 if elm.find("%sname" % ns).text == pkg_name:
855 if elm.find("%sarch" % ns).text != "src":
856 version = elm.find("%sversion" % ns)
857 tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
858 if tmpver > ver:
859 ver = tmpver
860 fmt = elm.find("%sformat" % ns)
861 if fmt:
862 fns = fmt.getchildren()[0].tag
863 fns = fns[0:fns.rindex("}")+1]
864 pkgpath = fmt.find("%ssourcerpm" % fns).text
865 target_repo = repo
866 break
867
868 if repo["primary"].endswith(".sqlite"):
869 con = sqlite.connect(repo["primary"])
870 for row in con.execute("select version, release, rpm_sourcerpm from packages where name = \"%s\" and arch != \"src\"" % pkg_name):
871 tmpver = "%s-%s" % (row[0], row[1])
872 if tmpver > ver:
873 pkgpath = "%s" % row[2]
874 target_repo = repo
875 break
876 con.close()
877 if target_repo:
878 return get_src_name(pkgpath)
879 else:
880 return None
881
882def get_pkglist_in_patterns(group, patterns):
883 found = False
884 pkglist = []
885 try:
886 root = xmlparse(patterns)
887 except SyntaxError:
888 raise SyntaxError("%s syntax error." % patterns)
889
890 for elm in list(root.getroot()):
891 ns = elm.tag
892 ns = ns[0:ns.rindex("}")+1]
893 name = elm.find("%sname" % ns)
894 summary = elm.find("%ssummary" % ns)
895 if name.text == group or summary.text == group:
896 found = True
897 break
898
899 if not found:
900 return pkglist
901
902 found = False
903 for requires in list(elm):
904 if requires.tag.endswith("requires"):
905 found = True
906 break
907
908 if not found:
909 return pkglist
910
911 for pkg in list(requires):
912 pkgname = pkg.attrib["name"]
913 if pkgname not in pkglist:
914 pkglist.append(pkgname)
915
916 return pkglist
917
918def get_pkglist_in_comps(group, comps):
919 found = False
920 pkglist = []
921 try:
922 root = xmlparse(comps)
923 except SyntaxError:
924 raise SyntaxError("%s syntax error." % comps)
925
926 for elm in root.getiterator("group"):
927 id = elm.find("id")
928 name = elm.find("name")
929 if id.text == group or name.text == group:
930 packagelist = elm.find("packagelist")
931 found = True
932 break
933
934 if not found:
935 return pkglist
936
937 for require in elm.getiterator("packagereq"):
938 if require.tag.endswith("packagereq"):
939 pkgname = require.text
940 if pkgname not in pkglist:
941 pkglist.append(pkgname)
942
943 return pkglist
944
945def is_statically_linked(binary):
946 return ", statically linked, " in runner.outs(['file', binary])
947
948def setup_qemu_emulator(rootdir, arch):
949 # mount binfmt_misc if it doesn't exist
950 if not os.path.exists("/proc/sys/fs/binfmt_misc"):
951 modprobecmd = find_binary_path("modprobe")
952 runner.show([modprobecmd, "binfmt_misc"])
953 if not os.path.exists("/proc/sys/fs/binfmt_misc/register"):
954 mountcmd = find_binary_path("mount")
955 runner.show([mountcmd, "-t", "binfmt_misc", "none", "/proc/sys/fs/binfmt_misc"])
956
957 # qemu_emulator is a special case, we can't use find_binary_path
958 # qemu emulator should be a statically-linked executable file
959 qemu_emulator = "/usr/bin/qemu-arm"
960 if not os.path.exists(qemu_emulator) or not is_statically_linked(qemu_emulator):
961 qemu_emulator = "/usr/bin/qemu-arm-static"
962 if not os.path.exists(qemu_emulator):
963 raise CreatorError("Please install a statically-linked qemu-arm")
964
965 # qemu emulator version check
966 armv7_list = [arch for arch in rpmmisc.archPolicies.keys() if arch.startswith('armv7')]
967 if arch in armv7_list: # need qemu (>=0.13.0)
968 qemuout = runner.outs([qemu_emulator, "-h"])
969 m = re.search("version\s*([.\d]+)", qemuout)
970 if m:
971 qemu_version = m.group(1)
972 if qemu_version < "0.13":
973 raise CreatorError("Requires %s version >=0.13 for %s" % (qemu_emulator, arch))
974 else:
975 msger.warning("Can't get version info of %s, please make sure it's higher than 0.13.0" % qemu_emulator)
976
977 if not os.path.exists(rootdir + "/usr/bin"):
978 makedirs(rootdir + "/usr/bin")
979 shutil.copy(qemu_emulator, rootdir + "/usr/bin/qemu-arm-static")
980 qemu_emulator = "/usr/bin/qemu-arm-static"
981
982 # disable selinux, selinux will block qemu emulator to run
983 if os.path.exists("/usr/sbin/setenforce"):
984 msger.info('Try to disable selinux')
985 runner.show(["/usr/sbin/setenforce", "0"])
986
987 # unregister it if it has been registered and is a dynamically-linked executable
988 node = "/proc/sys/fs/binfmt_misc/arm"
989 if os.path.exists(node):
990 qemu_unregister_string = "-1\n"
991 fd = open("/proc/sys/fs/binfmt_misc/arm", "w")
992 fd.write(qemu_unregister_string)
993 fd.close()
994
995 # register qemu emulator for interpreting other arch executable file
996 if not os.path.exists(node):
997 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
998 fd = open("/proc/sys/fs/binfmt_misc/register", "w")
999 fd.write(qemu_arm_string)
1000 fd.close()
1001
1002 return qemu_emulator
1003
1004def SrcpkgsDownload(pkgs, repometadata, instroot, cachedir):
1005 def get_source_repometadata(repometadata):
1006 src_repometadata=[]
1007 for repo in repometadata:
1008 if repo["name"].endswith("-source"):
1009 src_repometadata.append(repo)
1010 if src_repometadata:
1011 return src_repometadata
1012 return None
1013
1014 def get_src_name(srpm):
1015 m = SRPM_RE.match(srpm)
1016 if m:
1017 return m.group(1)
1018 return None
1019
1020 src_repometadata = get_source_repometadata(repometadata)
1021
1022 if not src_repometadata:
1023 msger.warning("No source repo found")
1024 return None
1025
1026 src_pkgs = []
1027 lpkgs_dict = {}
1028 lpkgs_path = []
1029 for repo in src_repometadata:
1030 cachepath = "%s/%s/packages/*.src.rpm" %(cachedir, repo["name"])
1031 lpkgs_path += glob.glob(cachepath)
1032
1033 for lpkg in lpkgs_path:
1034 lpkg_name = get_src_name(os.path.basename(lpkg))
1035 lpkgs_dict[lpkg_name] = lpkg
1036 localpkgs = lpkgs_dict.keys()
1037
1038 cached_count = 0
1039 destdir = instroot+'/usr/src/SRPMS'
1040 if not os.path.exists(destdir):
1041 os.makedirs(destdir)
1042
1043 srcpkgset = set()
1044 for _pkg in pkgs:
1045 srcpkg_name = get_source_name(_pkg, repometadata)
1046 if not srcpkg_name:
1047 continue
1048 srcpkgset.add(srcpkg_name)
1049
1050 for pkg in list(srcpkgset):
1051 if pkg in localpkgs:
1052 cached_count += 1
1053 shutil.copy(lpkgs_dict[pkg], destdir)
1054 src_pkgs.append(os.path.basename(lpkgs_dict[pkg]))
1055 else:
1056 src_pkg = get_package(pkg, src_repometadata, 'src')
1057 if src_pkg:
1058 shutil.copy(src_pkg, destdir)
1059 src_pkgs.append(src_pkg)
1060 msger.info("%d source packages gotten from cache" % cached_count)
1061
1062 return src_pkgs
1063
1064def strip_end(text, suffix):
1065 if not text.endswith(suffix):
1066 return text
1067 return text[:-len(suffix)]