fix run error issue for parser repomd.xml when here is group type
[tools/mic.git] / mic / utils / misc.py
old mode 100644 (file)
new mode 100755 (executable)
index 71315d6..399fd4e
@@ -15,6 +15,7 @@
 # with this program; if not, write to the Free Software Foundation, Inc., 59
 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 # with this program; if not, write to the Free Software Foundation, Inc., 59
 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
+from __future__ import with_statement
 import os
 import sys
 import time
 import os
 import sys
 import time
@@ -25,9 +26,8 @@ import glob
 import hashlib
 import subprocess
 import platform
 import hashlib
 import subprocess
 import platform
-import rpmmisc
-import hashlib
-import sqlite3 as sqlite
+import traceback
+
 
 try:
     import sqlite3 as sqlite
 
 try:
     import sqlite3 as sqlite
@@ -40,37 +40,35 @@ except ImportError:
     import cElementTree
 xmlparse = cElementTree.parse
 
     import cElementTree
 xmlparse = cElementTree.parse
 
-from errors import *
-from fs_related import *
-from rpmmisc import myurlgrab
-from proxy import get_proxy_for
-import runner
-
 from mic import msger
 from mic import msger
+from mic.archive import get_archive_suffixes
+from mic.utils.errors import CreatorError, SquashfsError
+from mic.utils.fs_related import find_binary_path, makedirs
+from mic.utils.grabber import myurlgrab
+from mic.utils.proxy import get_proxy_for
+from mic.utils import runner
+from mic.utils import rpmmisc
+from mic.utils.safeurl import SafeURL
+
 
 RPM_RE  = re.compile("(.*)\.(.*) (.*)-(.*)")
 
 RPM_RE  = re.compile("(.*)\.(.*) (.*)-(.*)")
-RPM_FMT = "%(name)s.%(arch)s %(ver_rel)s"
+RPM_FMT = "%(name)s.%(arch)s %(version)s-%(release)s"
 SRPM_RE = re.compile("(.*)-(\d+.*)-(\d+\.\d+).src.rpm")
 
 SRPM_RE = re.compile("(.*)-(\d+.*)-(\d+\.\d+).src.rpm")
 
-def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
+
+def build_name(kscfg, release=None, prefix = None, suffix = None):
     """Construct and return an image name string.
 
     This is a utility function to help create sensible name and fslabel
     strings. The name is constructed using the sans-prefix-and-extension
     kickstart filename and the supplied prefix and suffix.
 
     """Construct and return an image name string.
 
     This is a utility function to help create sensible name and fslabel
     strings. The name is constructed using the sans-prefix-and-extension
     kickstart filename and the supplied prefix and suffix.
 
-    If the name exceeds the maxlen length supplied, the prefix is first dropped
-    and then the kickstart filename portion is reduced until it fits. In other
-    words, the suffix takes precedence over the kickstart portion and the
-    kickstart portion takes precedence over the prefix.
-
     kscfg -- a path to a kickstart file
     kscfg -- a path to a kickstart file
+    release --  a replacement to suffix for image release
     prefix -- a prefix to prepend to the name; defaults to None, which causes
               no prefix to be used
     suffix -- a suffix to append to the name; defaults to None, which causes
               a YYYYMMDDHHMM suffix to be used
     prefix -- a prefix to prepend to the name; defaults to None, which causes
               no prefix to be used
     suffix -- a suffix to append to the name; defaults to None, which causes
               a YYYYMMDDHHMM suffix to be used
-    maxlen -- the maximum length for the returned string; defaults to None,
-              which means there is no restriction on the name length
 
     Note, if maxlen is less then the len(suffix), you get to keep both pieces.
 
 
     Note, if maxlen is less then the len(suffix), you get to keep both pieces.
 
@@ -80,6 +78,8 @@ def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
     if idx >= 0:
         name = name[:idx]
 
     if idx >= 0:
         name = name[:idx]
 
+    if release is not None:
+        suffix = ""
     if prefix is None:
         prefix = ""
     if suffix is None:
     if prefix is None:
         prefix = ""
     if suffix is None:
@@ -88,10 +88,10 @@ def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
     if name.startswith(prefix):
         name = name[len(prefix):]
 
     if name.startswith(prefix):
         name = name[len(prefix):]
 
-    ret = prefix + name + "-" + suffix
-    if not maxlen is None and len(ret) > maxlen:
-        ret = name[:maxlen - len(suffix) - 1] + "-" + suffix
+    prefix = "%s-" % prefix if prefix else ""
+    suffix = "-%s" % suffix if suffix else ""
 
 
+    ret = prefix + name + suffix
     return ret
 
 def get_distro():
     return ret
 
 def get_distro():
@@ -115,18 +115,25 @@ def get_distro():
 
     return (dist, ver, id)
 
 
     return (dist, ver, id)
 
-def get_distro_str():
+def get_hostname():
+    """Get hostname
+    """
+    return platform.node()
+
+def get_hostname_distro_str():
     """Get composited string for current linux distribution
     """
     (dist, ver, id) = get_distro()
     """Get composited string for current linux distribution
     """
     (dist, ver, id) = get_distro()
+    hostname = get_hostname()
 
     if not dist:
 
     if not dist:
-        return 'Unknown Linux Distro'
+        return "%s(Unknown Linux Distribution)" % hostname
     else:
     else:
-        distro_str = ' '.join(map(str.strip, (dist, ver, id)))
+        distro_str = ' '.join(map(str.strip, (hostname, dist, ver, id)))
         return distro_str.strip()
 
 _LOOP_RULE_PTH = None
         return distro_str.strip()
 
 _LOOP_RULE_PTH = None
+
 def hide_loopdev_presentation():
     udev_rules = "80-prevent-loop-present.rules"
     udev_rules_dir = [
 def hide_loopdev_presentation():
     udev_rules = "80-prevent-loop-present.rules"
     udev_rules_dir = [
@@ -135,6 +142,8 @@ def hide_loopdev_presentation():
                        '/etc/udev/rules.d/'
                      ]
 
                        '/etc/udev/rules.d/'
                      ]
 
+    global _LOOP_RULE_PTH
+
     for rdir in udev_rules_dir:
         if os.path.exists(rdir):
             _LOOP_RULE_PTH = os.path.join(rdir, udev_rules)
     for rdir in udev_rules_dir:
         if os.path.exists(rdir):
             _LOOP_RULE_PTH = os.path.join(rdir, udev_rules)
@@ -151,6 +160,8 @@ def hide_loopdev_presentation():
         pass
 
 def unhide_loopdev_presentation():
         pass
 
 def unhide_loopdev_presentation():
+    #global _LOOP_RULE_PTH
+
     if not _LOOP_RULE_PTH:
         return
 
     if not _LOOP_RULE_PTH:
         return
 
@@ -171,88 +182,12 @@ def extract_rpm(rpmfile, targetdir):
     p1 = subprocess.Popen([rpm2cpio, rpmfile], stdout=subprocess.PIPE)
     p2 = subprocess.Popen([cpio, "-idv"], stdin=p1.stdout,
                           stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     p1 = subprocess.Popen([rpm2cpio, rpmfile], stdout=subprocess.PIPE)
     p2 = subprocess.Popen([cpio, "-idv"], stdin=p1.stdout,
                           stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    p1.stdout.close()
     (sout, serr) = p2.communicate()
     msger.verbose(sout or serr)
 
     os.chdir(olddir)
 
     (sout, serr) = p2.communicate()
     msger.verbose(sout or serr)
 
     os.chdir(olddir)
 
-def compressing(fpath, method):
-    comp_map = {
-        "gz": "gzip",
-        "bz2": "bzip2"
-    }
-    if method not in comp_map:
-        raise CreatorError("Unsupport compress format: %s, valid values: %s"
-                           % (method, ','.join(comp_map.keys())))
-    cmd = find_binary_path(comp_map[method])
-    rc = runner.show([cmd, "-f", fpath])
-    if rc:
-        raise CreatorError("Failed to %s file: %s" % (comp_map[method], fpath))
-
-def taring(dstfile, target):
-    import tarfile
-    basen, ext = os.path.splitext(dstfile)
-    comp = {".tar": None,
-            ".gz": "gz", # for .tar.gz
-            ".bz2": "bz2", # for .tar.bz2
-            ".tgz": "gz",
-            ".tbz": "bz2"}[ext]
-
-    # specify tarball file path
-    if not comp:
-        tarpath = dstfile
-    elif basen.endswith(".tar"):
-        tarpath = basen
-    else:
-        tarpath = basen + ".tar"
-    wf = tarfile.open(tarpath, 'w')
-
-    if os.path.isdir(target):
-        for item in os.listdir(target):
-            wf.add(os.path.join(target, item), item)
-    else:
-        wf.add(target, os.path.basename(target))
-    wf.close()
-
-    if comp:
-        compressing(tarpath, comp)
-        # when dstfile ext is ".tgz" and ".tbz", should rename
-        if not basen.endswith(".tar"):
-            shutil.move("%s.%s" % (tarpath, comp), dstfile)
-
-def ziping(dstfile, target):
-    import zipfile
-    wf = zipfile.ZipFile(dstfile, 'w', compression=zipfile.ZIP_DEFLATED)
-    if os.path.isdir(target):
-        for item in os.listdir(target):
-            fpath = os.path.join(target, item)
-            if not os.path.isfile(fpath):
-                continue
-            wf.write(fpath, item, zipfile.ZIP_DEFLATED)
-    else:
-        wf.write(target, os.path.basename(target), zipfile.ZIP_DEFLATED)
-    wf.close()
-
-pack_formats = {
-    ".tar": taring,
-    ".tar.gz": taring,
-    ".tar.bz2": taring,
-    ".tgz": taring,
-    ".tbz": taring,
-    ".zip": ziping,
-}
-
-def packing(dstfile, target):
-    (base, ext) = os.path.splitext(dstfile)
-    if ext in (".gz", ".bz2") and base.endswith(".tar"):
-        ext = ".tar" + ext
-    if ext not in pack_formats:
-        raise CreatorError("Unsupport pack format: %s, valid values: %s"
-                           % (ext, ','.join(pack_formats.keys())))
-    func = pack_formats[ext]
-    # func should be callable
-    func(dstfile, target)
-
 def human_size(size):
     """Return human readable string for Bytes size
     """
 def human_size(size):
     """Return human readable string for Bytes size
     """
@@ -265,6 +200,18 @@ def human_size(size):
     mant = float(size/math.pow(1024, expo))
     return "{0:.1f}{1:s}".format(mant, measure[expo])
 
     mant = float(size/math.pow(1024, expo))
     return "{0:.1f}{1:s}".format(mant, measure[expo])
 
+def get_block_size(file_obj):
+    """ Returns block size for file object 'file_obj'. Errors are indicated by
+    the 'IOError' exception. """
+
+    from fcntl import ioctl
+    import struct
+
+    # Get the block size of the host file-system for the image file by calling
+    # the FIGETBSZ ioctl (number 2).
+    binary_data = ioctl(file_obj, 2, struct.pack('I', 0))
+    return struct.unpack('I', binary_data)[0]
+
 def check_space_pre_cp(src, dst):
     """Check whether disk space is enough before 'cp' like
     operations, else exception will be raised.
 def check_space_pre_cp(src, dst):
     """Check whether disk space is enough before 'cp' like
     operations, else exception will be raised.
@@ -288,7 +235,7 @@ def calc_hashes(file_path, hash_names, start = 0, end = None):
         end = os.path.getsize(file_path)
 
     chunk_size = 65536
         end = os.path.getsize(file_path)
 
     chunk_size = 65536
-    to_read = end - start;
+    to_read = end - start
     read = 0
 
     hashes = []
     read = 0
 
     hashes = []
@@ -315,15 +262,21 @@ def calc_hashes(file_path, hash_names, start = 0, end = None):
 def get_md5sum(fpath):
     return calc_hashes(fpath, ('md5', ))[0]
 
 def get_md5sum(fpath):
     return calc_hashes(fpath, ('md5', ))[0]
 
+def get_sha1sum(fpath):
+    return calc_hashes(fpath, ('sha1', ))[0]
+
+def get_sha256sum(fpath):
+    return calc_hashes(fpath, ('sha256', ))[0]
+
 def normalize_ksfile(ksconf, release, arch):
 def normalize_ksfile(ksconf, release, arch):
-    def _clrtempks():
-        try:
-            os.unlink(ksconf)
-        except:
-            pass
+    '''
+    Return the name of a normalized ks file in which macro variables
+    @BUILD_ID@ and @ARCH@ are replace with real values.
 
 
-    if not os.path.exists(ksconf):
-        return
+    The original ks file is returned if no special macro is used, otherwise
+    a temp file is created and returned, which will be deleted when program
+    exits normally.
+    '''
 
     if not release:
         release = "latest"
 
     if not release:
         release = "latest"
@@ -333,21 +286,31 @@ def normalize_ksfile(ksconf, release, arch):
     with open(ksconf) as f:
         ksc = f.read()
 
     with open(ksconf) as f:
         ksc = f.read()
 
-    if "@ARCH@" in ksc or "@BUILD_ID@" in ksc:
-        msger.info("Substitute macro variable @BUILD_ID@/@ARCH@ in ks: %s" % ksconf)
-        ksc = ksc.replace("@ARCH@", arch)
-        ksc = ksc.replace("@BUILD_ID@", release)
-        fd, ksconf = tempfile.mkstemp(prefix=os.path.basename(ksconf), dir="/tmp/")
-        os.write(fd, ksc)
-        os.close(fd)
+    if "@ARCH@" not in ksc and "@BUILD_ID@" not in ksc:
+        return ksconf
+
+    msger.info("Substitute macro variable @BUILD_ID@/@ARCH@ in ks: %s" % ksconf)
+    ksc = ksc.replace("@ARCH@", arch)
+    ksc = ksc.replace("@BUILD_ID@", release)
+
+    fd, ksconf = tempfile.mkstemp(prefix=os.path.basename(ksconf))
+    os.write(fd, ksc)
+    os.close(fd)
+
+    msger.debug('normalized ks file:%s' % ksconf)
 
 
-        msger.debug('new ks path %s' % ksconf)
+    def remove_temp_ks():
+        try:
+            os.unlink(ksconf)
+        except OSError as err:
+            msger.warning('Failed to remove temp ks file:%s:%s' % (ksconf, err))
 
 
-        import atexit
-        atexit.register(_clrtempks)
+    import atexit
+    atexit.register(remove_temp_ks)
 
     return ksconf
 
 
     return ksconf
 
+
 def _check_mic_chroot(rootdir):
     def _path(path):
         return rootdir.rstrip('/') + path
 def _check_mic_chroot(rootdir):
     def _path(path):
         return rootdir.rstrip('/') + path
@@ -437,22 +400,23 @@ def get_image_type(path):
     else:
         raise CreatorError("Cannot detect the type of image: %s" % path)
 
     else:
         raise CreatorError("Cannot detect the type of image: %s" % path)
 
-def get_file_size(file):
+
+def get_file_size(filename):
     """ Return size in MB unit """
     """ Return size in MB unit """
-    rc, duOutput  = runner.runtool(['du', "-s", "-b", "-B", "1M", file])
+    cmd = ['du', "-s", "-b", "-B", "1M", filename]
+    rc, duOutput  = runner.runtool(cmd)
     if rc != 0:
     if rc != 0:
-        raise CreatorError("Failed to run %s" % du)
-
+        raise CreatorError("Failed to run: %s" % ' '.join(cmd))
     size1 = int(duOutput.split()[0])
     size1 = int(duOutput.split()[0])
-    rc, duOutput = runner.runtool(['du', "-s", "-B", "1M", file])
+
+    cmd = ['du', "-s", "-B", "1M", filename]
+    rc, duOutput = runner.runtool(cmd)
     if rc != 0:
     if rc != 0:
-        raise CreatorError("Failed to run %s" % du)
+        raise CreatorError("Failed to run: %s" % ' '.join(cmd))
 
     size2 = int(duOutput.split()[0])
 
     size2 = int(duOutput.split()[0])
-    if size1 > size2:
-        return size1
-    else:
-        return size2
+    return max(size1, size2)
+
 
 def get_filesystem_avail(fs):
     vfstat = os.statvfs(fs)
 
 def get_filesystem_avail(fs):
     vfstat = os.statvfs(fs)
@@ -523,13 +487,17 @@ def get_repostrs_from_ks(ks):
 
         if 'name' not in repo:
             repo['name'] = _get_temp_reponame(repodata.baseurl)
 
         if 'name' not in repo:
             repo['name'] = _get_temp_reponame(repodata.baseurl)
+        if hasattr(repodata, 'baseurl') and getattr(repodata, 'baseurl'):
+            repo['baseurl'] = SafeURL(getattr(repodata, 'baseurl'),
+                                      getattr(repodata, 'user', None),
+                                      getattr(repodata, 'passwd', None))
 
         kickstart_repos.append(repo)
 
     return kickstart_repos
 
 def _get_uncompressed_data_from_url(url, filename, proxies):
 
         kickstart_repos.append(repo)
 
     return kickstart_repos
 
 def _get_uncompressed_data_from_url(url, filename, proxies):
-    filename = myurlgrab(url, filename, proxies)
+    filename = myurlgrab(url.full, filename, proxies)
     suffix = None
     if filename.endswith(".gz"):
         suffix = ".gz"
     suffix = None
     if filename.endswith(".gz"):
         suffix = ".gz"
@@ -543,7 +511,7 @@ def _get_uncompressed_data_from_url(url, filename, proxies):
 
 def _get_metadata_from_repo(baseurl, proxies, cachedir, reponame, filename,
                             sumtype=None, checksum=None):
 
 def _get_metadata_from_repo(baseurl, proxies, cachedir, reponame, filename,
                             sumtype=None, checksum=None):
-    url = os.path.join(baseurl, filename)
+    url = baseurl.join(filename)
     filename_tmp = str("%s/%s/%s" % (cachedir, reponame, os.path.basename(filename)))
     if os.path.splitext(filename_tmp)[1] in (".gz", ".bz2"):
         filename = os.path.splitext(filename_tmp)[0]
     filename_tmp = str("%s/%s/%s" % (cachedir, reponame, os.path.basename(filename)))
     if os.path.splitext(filename_tmp)[1] in (".gz", ".bz2"):
         filename = os.path.splitext(filename_tmp)[0]
@@ -565,23 +533,22 @@ def _get_metadata_from_repo(baseurl, proxies, cachedir, reponame, filename,
 def get_metadata_from_repos(repos, cachedir):
     my_repo_metadata = []
     for repo in repos:
 def get_metadata_from_repos(repos, cachedir):
     my_repo_metadata = []
     for repo in repos:
-        reponame = repo['name']
-        baseurl  = repo['baseurl']
-
+        reponame = repo.name
+        baseurl = repo.baseurl
 
 
-        if 'proxy' in repo:
-            proxy = repo['proxy']
+        if hasattr(repo, 'proxy'):
+            proxy = repo.proxy
         else:
             proxy = get_proxy_for(baseurl)
 
         proxies = None
         if proxy:
         else:
             proxy = get_proxy_for(baseurl)
 
         proxies = None
         if proxy:
-           proxies = {str(baseurl.split(":")[0]):str(proxy)}
+            proxies = {str(baseurl.split(":")[0]): str(proxy)}
 
         makedirs(os.path.join(cachedir, reponame))
 
         makedirs(os.path.join(cachedir, reponame))
-        url = os.path.join(baseurl, "repodata/repomd.xml")
+        url = baseurl.join("repodata/repomd.xml")
         filename = os.path.join(cachedir, reponame, 'repomd.xml')
         filename = os.path.join(cachedir, reponame, 'repomd.xml')
-        repomd = myurlgrab(url, filename, proxies)
+        repomd = myurlgrab(url.full, filename, proxies)
         try:
             root = xmlparse(repomd)
         except SyntaxError:
         try:
             root = xmlparse(repomd)
         except SyntaxError:
@@ -602,7 +569,8 @@ def get_metadata_from_repos(repos, cachedir):
                 break
 
         for elm in root.getiterator("%sdata" % ns):
                 break
 
         for elm in root.getiterator("%sdata" % ns):
-            if elm.attrib["type"] in ("group_gz", "group"):
+            #"group" type has no "open-checksum" filed, remove it.
+            if elm.attrib["type"] == "group_gz":
                 filepaths['comps'] = elm.find("%slocation" % ns).attrib['href']
                 checksums['comps'] = elm.find("%sopen-checksum" % ns).text
                 sumtypes['comps'] = elm.find("%sopen-checksum" % ns).attrib['type']
                 filepaths['comps'] = elm.find("%slocation" % ns).attrib['href']
                 checksums['comps'] = elm.find("%sopen-checksum" % ns).text
                 sumtypes['comps'] = elm.find("%sopen-checksum" % ns).attrib['type']
@@ -653,7 +621,8 @@ def get_metadata_from_repos(repos, cachedir):
                                  "proxies":proxies,
                                  "patterns":filepaths['patterns'],
                                  "comps":filepaths['comps'],
                                  "proxies":proxies,
                                  "patterns":filepaths['patterns'],
                                  "comps":filepaths['comps'],
-                                 "repokey":repokey})
+                                 "repokey":repokey,
+                                 "priority":repo.priority})
 
     return my_repo_metadata
 
 
     return my_repo_metadata
 
@@ -687,35 +656,8 @@ def get_rpmver_in_repo(repometadata):
     return None
 
 def get_arch(repometadata):
     return None
 
 def get_arch(repometadata):
-    def uniqarch(archlist=[]):
-        uniq_arch = []
-        for i in range(len(archlist)):
-            if archlist[i] not in rpmmisc.archPolicies.keys():
-                continue
-            need_append = True
-            j = 0
-            while j < len(uniq_arch):
-                if archlist[i] in rpmmisc.archPolicies[uniq_arch[j]].split(':'):
-                    need_append = False
-                    break
-                if uniq_arch[j] in rpmmisc.archPolicies[archlist[i]].split(':'):
-                    if need_append:
-                        uniq_arch[j] = archlist[i]
-                        need_append = False
-                    else:
-                        uniq_arch.remove(uniq_arch[j])
-                        continue
-                j += 1
-            if need_append:
-                 uniq_arch.append(archlist[i])
-
-        return uniq_arch
-    
-
-    ret_uniq_arch = []
-    ret_arch_list = []
+    archlist = []
     for repo in repometadata:
     for repo in repometadata:
-        archlist = []
         if repo["primary"].endswith(".xml"):
             root = xmlparse(repo["primary"])
             ns = root.getroot().tag
         if repo["primary"].endswith(".xml"):
             root = xmlparse(repo["primary"])
             ns = root.getroot().tag
@@ -733,16 +675,32 @@ def get_arch(repometadata):
 
             con.close()
 
 
             con.close()
 
-        uniq_arch = uniqarch(archlist)
-        if not ret_uniq_arch and len(uniq_arch) == 1:
-            ret_uniq_arch = uniq_arch 
-        ret_arch_list += uniq_arch
+    uniq_arch = []
+    for i in range(len(archlist)):
+        if archlist[i] not in rpmmisc.archPolicies.keys():
+            continue
+        need_append = True
+        j = 0
+        while j < len(uniq_arch):
+            if archlist[i] in rpmmisc.archPolicies[uniq_arch[j]].split(':'):
+                need_append = False
+                break
+            if uniq_arch[j] in rpmmisc.archPolicies[archlist[i]].split(':'):
+                if need_append:
+                    uniq_arch[j] = archlist[i]
+                    need_append = False
+                else:
+                    uniq_arch.remove(uniq_arch[j])
+                    continue
+            j += 1
+        if need_append:
+             uniq_arch.append(archlist[i])
 
 
-    ret_arch_list = uniqarch(ret_arch_list)
-    return ret_uniq_arch, ret_arch_list
+    return uniq_arch, archlist
 
 def get_package(pkg, repometadata, arch = None):
     ver = ""
 
 def get_package(pkg, repometadata, arch = None):
     ver = ""
+    priority = 99
     target_repo = None
     if not arch:
         arches = []
     target_repo = None
     if not arch:
         arches = []
@@ -758,16 +716,25 @@ def get_package(pkg, repometadata, arch = None):
             ns = root.getroot().tag
             ns = ns[0:ns.rindex("}")+1]
             for elm in root.getiterator("%spackage" % ns):
             ns = root.getroot().tag
             ns = ns[0:ns.rindex("}")+1]
             for elm in root.getiterator("%spackage" % ns):
-                if elm.find("%sname" % ns).text == pkg:
-                    if elm.find("%sarch" % ns).text in arches:
-                        version = elm.find("%sversion" % ns)
-                        tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
-                        if tmpver > ver:
-                            ver = tmpver
+                if elm.find("%sname" % ns).text == pkg and elm.find("%sarch" % ns).text in arches:
+                    if repo["priority"] != None:
+                        tmpprior = int(repo["priority"])
+                        if tmpprior < priority:
+                            priority = tmpprior
                             location = elm.find("%slocation" % ns)
                             pkgpath = "%s" % location.attrib['href']
                             target_repo = repo
                             location = elm.find("%slocation" % ns)
                             pkgpath = "%s" % location.attrib['href']
                             target_repo = repo
-                        break
+                            break
+                        elif tmpprior > priority:
+                            break
+                    version = elm.find("%sversion" % ns)
+                    tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
+                    if tmpver > ver:
+                        ver = tmpver
+                        location = elm.find("%slocation" % ns)
+                        pkgpath = "%s" % location.attrib['href']
+                        target_repo = repo
+                    break
         if repo["primary"].endswith(".sqlite"):
             con = sqlite.connect(repo["primary"])
             if arch:
         if repo["primary"].endswith(".sqlite"):
             con = sqlite.connect(repo["primary"])
             if arch:
@@ -794,7 +761,7 @@ def get_package(pkg, repometadata, arch = None):
             con.close()
     if target_repo:
         makedirs("%s/packages/%s" % (target_repo["cachedir"], target_repo["name"]))
             con.close()
     if target_repo:
         makedirs("%s/packages/%s" % (target_repo["cachedir"], target_repo["name"]))
-        url = os.path.join(target_repo["baseurl"], pkgpath)
+        url = target_repo["baseurl"].join(pkgpath)
         filename = str("%s/packages/%s/%s" % (target_repo["cachedir"], target_repo["name"], os.path.basename(pkgpath)))
         if os.path.exists(filename):
             ret = rpmmisc.checkRpmIntegrity('rpm', filename)
         filename = str("%s/packages/%s/%s" % (target_repo["cachedir"], target_repo["name"], os.path.basename(pkgpath)))
         if os.path.exists(filename):
             ret = rpmmisc.checkRpmIntegrity('rpm', filename)
@@ -805,7 +772,7 @@ def get_package(pkg, repometadata, arch = None):
                           (os.path.basename(filename), filename))
             os.unlink(filename)
 
                           (os.path.basename(filename), filename))
             os.unlink(filename)
 
-        pkg = myurlgrab(str(url), filename, target_repo["proxies"])
+        pkg = myurlgrab(url.full, filename, target_repo["proxies"])
         return pkg
     else:
         return None
         return pkg
     else:
         return None
@@ -931,7 +898,38 @@ def get_pkglist_in_comps(group, comps):
 def is_statically_linked(binary):
     return ", statically linked, " in runner.outs(['file', binary])
 
 def is_statically_linked(binary):
     return ", statically linked, " in runner.outs(['file', binary])
 
+def get_qemu_arm_binary(arch):
+    if arch == "aarch64":
+        node = "/proc/sys/fs/binfmt_misc/aarch64"
+        if os.path.exists("/usr/bin/qemu-arm64") and is_statically_linked("/usr/bin/qemu-arm64"):
+            arm_binary = "qemu-arm64"
+        elif os.path.exists("/usr/bin/qemu-aarch64") and is_statically_linked("/usr/bin/qemu-aarch64"):
+            arm_binary = "qemu-aarch64"
+        elif os.path.exists("/usr/bin/qemu-arm64-static"):
+            arm_binary = "qemu-arm64-static"
+        elif os.path.exists("/usr/bin/qemu-aarch64-static"):
+            arm_binary = "qemu-aarch64-static"
+        else:
+            raise CreatorError("Please install a statically-linked %s" % arm_binary)
+    elif arch == "mipsel":
+        node = "/proc/sys/fs/binfmt_misc/mipsel"
+        arm_binary = "qemu-mipsel"
+        if not os.path.exists("/usr/bin/%s" % arm_binary) or not is_statically_linked("/usr/bin/%s"):
+            arm_binary = "qemu-mipsel-static"
+        if not os.path.exists("/usr/bin/%s" % arm_binary):
+            raise CreatorError("Please install a statically-linked %s" % arm_binary)
+    else:
+        node = "/proc/sys/fs/binfmt_misc/arm"
+        arm_binary = "qemu-arm"
+        if not os.path.exists("/usr/bin/qemu-arm") or not is_statically_linked("/usr/bin/qemu-arm"):
+            arm_binary = "qemu-arm-static"
+        if not os.path.exists("/usr/bin/%s" % arm_binary):
+            raise CreatorError("Please install a statically-linked %s" % arm_binary)
+
+    return (arm_binary, node)
+
 def setup_qemu_emulator(rootdir, arch):
 def setup_qemu_emulator(rootdir, arch):
+    qemu_emulators = []
     # mount binfmt_misc if it doesn't exist
     if not os.path.exists("/proc/sys/fs/binfmt_misc"):
         modprobecmd = find_binary_path("modprobe")
     # mount binfmt_misc if it doesn't exist
     if not os.path.exists("/proc/sys/fs/binfmt_misc"):
         modprobecmd = find_binary_path("modprobe")
@@ -942,52 +940,50 @@ def setup_qemu_emulator(rootdir, arch):
 
     # qemu_emulator is a special case, we can't use find_binary_path
     # qemu emulator should be a statically-linked executable file
 
     # qemu_emulator is a special case, we can't use find_binary_path
     # qemu emulator should be a statically-linked executable file
-    qemu_emulator = "/usr/bin/qemu-arm"
-    if not os.path.exists(qemu_emulator) or not is_statically_linked(qemu_emulator):
-        qemu_emulator = "/usr/bin/qemu-arm-static"
-    if not os.path.exists(qemu_emulator):
-        raise CreatorError("Please install a statically-linked qemu-arm")
-
-    # qemu emulator version check
-    armv7_list = [arch for arch in rpmmisc.archPolicies.keys() if arch.startswith('armv7')]
-    if arch in armv7_list:  # need qemu (>=0.13.0)
-        qemuout = runner.outs([qemu_emulator, "-h"])
-        m = re.search("version\s*([.\d]+)", qemuout)
-        if m:
-            qemu_version = m.group(1)
-            if qemu_version < "0.13":
-                raise CreatorError("Requires %s version >=0.13 for %s" % (qemu_emulator, arch))
-        else:
-            msger.warning("Can't get version info of %s, please make sure it's higher than 0.13.0" % qemu_emulator)
+    arm_binary, node = get_qemu_arm_binary(arch)
+    qemu_emulator = "/usr/bin/%s" % arm_binary
 
     if not os.path.exists(rootdir + "/usr/bin"):
         makedirs(rootdir + "/usr/bin")
     shutil.copy(qemu_emulator, rootdir + qemu_emulator)
 
     if not os.path.exists(rootdir + "/usr/bin"):
         makedirs(rootdir + "/usr/bin")
     shutil.copy(qemu_emulator, rootdir + qemu_emulator)
+    qemu_emulators.append(qemu_emulator)
 
     # disable selinux, selinux will block qemu emulator to run
     if os.path.exists("/usr/sbin/setenforce"):
         msger.info('Try to disable selinux')
         runner.show(["/usr/sbin/setenforce", "0"])
 
 
     # disable selinux, selinux will block qemu emulator to run
     if os.path.exists("/usr/sbin/setenforce"):
         msger.info('Try to disable selinux')
         runner.show(["/usr/sbin/setenforce", "0"])
 
-    node = "/proc/sys/fs/binfmt_misc/arm"
-    if is_statically_linked(qemu_emulator) and os.path.exists(node):
-        return qemu_emulator
-
-    # unregister it if it has been registered and is a dynamically-linked executable
-    if not is_statically_linked(qemu_emulator) and os.path.exists(node):
-        qemu_unregister_string = "-1\n"
-        fd = open("/proc/sys/fs/binfmt_misc/arm", "w")
-        fd.write(qemu_unregister_string)
-        fd.close()
-
     # register qemu emulator for interpreting other arch executable file
     if not os.path.exists(node):
     # register qemu emulator for interpreting other arch executable file
     if not os.path.exists(node):
-        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
-        fd = open("/proc/sys/fs/binfmt_misc/register", "w")
-        fd.write(qemu_arm_string)
-        fd.close()
+        if arch == "aarch64":
+            qemu_arm_string = ":aarch64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xb7:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff:%s:\n" % qemu_emulator
+        elif arch == "mipsel":
+            qemu_arm_string = ":mipsel:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x08\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:%s:\n" % qemu_emulator
+        else:
+            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
 
 
-    return qemu_emulator
+        with open("/proc/sys/fs/binfmt_misc/register", "w") as fd:
+            fd.write(qemu_arm_string)
+    else:
+        flags = ""
+        interpreter = ""
+        with open(node, "r") as fd:
+            for line in fd.readlines():
+                if line.startswith("flags:"):
+                    flags = line[len("flags:"):].strip()
+                elif line.startswith("interpreter"):
+                    interpreter = line[len("interpreter"):].strip()
+
+        if flags == "P" and interpreter.endswith("-binfmt"):
+            # copy binfmt wrapper when preserve-argv[0] flag is enabled
+            shutil.copy(os.path.realpath(interpreter), rootdir + interpreter)
+            qemu_emulators.append(interpreter)
+        elif not flags and interpreter != qemu_emulator:
+            # create symlink as registered qemu emulator
+            os.symlink(qemu_emulator, rootdir + interpreter)
+            qemu_emulators.append(interpreter)
+
+    return qemu_emulators
 
 def SrcpkgsDownload(pkgs, repometadata, instroot, cachedir):
     def get_source_repometadata(repometadata):
 
 def SrcpkgsDownload(pkgs, repometadata, instroot, cachedir):
     def get_source_repometadata(repometadata):
@@ -1053,3 +1049,11 @@ def strip_end(text, suffix):
     if not text.endswith(suffix):
         return text
     return text[:-len(suffix)]
     if not text.endswith(suffix):
         return text
     return text[:-len(suffix)]
+
+def strip_archive_suffix(filename):
+    for suffix in get_archive_suffixes():
+        if filename.endswith(suffix):
+            return filename[:-len(suffix)]
+    else:
+        msger.warning("Not supported archive file format: %s" % filename)
+    return None