new rt_utils to handle mic running in bootstrap
authorGui Chen <gui.chen@intel.com>
Wed, 15 Aug 2012 13:29:51 +0000 (21:29 +0800)
committerGui Chen <gui.chen@intel.com>
Wed, 15 Aug 2012 15:23:28 +0000 (23:23 +0800)
Signed-off-by: Gui Chen <gui.chen@intel.com>
mic/rt_util.py

index 04a5291..bb27bfe 100644 (file)
 # with this program; if not, write to the Free Software Foundation, Inc., 59
 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-import os, sys
-import string
-import shutil
+from __future__ import with_statement
+import os
+import sys
 import re
+import shutil
+import subprocess
 
-from mic import bootstrap
-from mic import msger
+from mic import bootstrap, msger
 from mic.conf import configmgr
-from mic.utils import errors
-import mic.utils.misc as misc
-from mic.utils.proxy import get_proxy_for
+from mic.utils import errors, proxy
+from mic.utils.fs_related import find_binary_path
+from mic.chroot import setup_chrootenv, cleanup_chrootenv
 
-BOOTSTRAP_URL="http://download.tizen.org/tools/micbootstrap"
+expath = lambda p: os.path.abspath(os.path.expanduser(p))
 
-def runmic_in_runtime(runmode, opts, ksfile, argv=None):
-    dist = misc.get_distro()[0]
-    if not runmode or not dist or "MeeGo" == dist:
-        return
+def bootstrap_mic(argv=None):
+
+
+    def mychroot():
+        os.chroot(rootdir)
+        os.chdir(cwd)
 
+    # by default, sys.argv is used to run mic in bootstrap
     if not argv:
         argv = sys.argv
-    else:
-        argv = argv[:]
+    if argv[0] not in ('/usr/bin/mic', 'mic'):
+        argv[0] = '/usr/bin/mic'
+
+    cropts = configmgr.create
+    bsopts = configmgr.bootstrap
+    distro = bsopts['distro_name'].lower()
+    if distro not in bsopts:
+        msger.info("Use native running for distro don't support bootstrap")
+        return
 
-    if runmode == 'bootstrap':
-        msger.info("Use bootstrap runtime environment")
-        name = "micbootstrap"
-        try:
-            repostrs = configmgr.bootstraps[name]
-        except:
-            repostrs = "name:%s,baseurl:%s," (name, BOOTSTRAP_URL)
-            proxy = get_proxy_for(BOOTSTRAP_URL)
-            if proxy:
-                repostrs += "proxy:%s" % proxy
-
-        repolist = []
-        if not name:
-            # use ks repo to create bootstrap
-            # so far it can't be effective for mic not in repo
-            #name = os.path.basename(ksfile)
-            #repostrs = misc.get_repostrs_from_ks(opts['ks'])
-            #for item in repostrs:
-            #    repolist.append(convert_repostr(item))
-            msger.info("cannot find valid bootstrap, please check the config")
-            msger.info("Back to native running")
-            return
-        else:
-            for reponame, repostr in repostrs.items():
-                repolist.append(convert_repostr(repostr))
-        runmic_in_bootstrap(name, argv, opts, ksfile, repolist)
-    else:
-        raise errors.RuntimeError('Invalid runmode: %s ' % runmode)
+    rootdir = bsopts['rootdir']
+    pkglist = bsopts[distro]
+    cwd = os.getcwd()
 
-    sys.exit(0)
+    # create bootstrap
+    bsenv = bootstrap.Bootstrap(rootdir)
+    try:
+        bsenv.create(cropts['repomd'], pkglist)
+        sync_mic(rootdir)
+    except errors.BootstrapError, err:
+        bsenv.cleanup()
+        msger.warning('\n%s' % err)
+        msger.info("Use native running for failure to create bootstrap")
+        return
 
-def compare_rpmversion(ver1, ver2):
-    return ver1.split('.')[0] == ver2.split('.')[0] and \
-        ver1.split('.')[1] == ver2.split('.')[1]
-
-def convert_repostr(repostr):
-    repo = {}
-    for item in repostr.split(','):
-        loc = item.find(':')
-        opt = item[0:loc]
-        if opt in ('name', 'baseurl', 'mirrolist', 'proxy', \
-            'proxy_username', 'proxy_password', 'debuginfo', \
-            'source', 'gpgkey', 'disable'):
-            if len(item) > loc:
-                repo[opt] = item[loc+1:]
-            else:
-                repo[opt] = None
-    return repo
-
-def select_bootstrap(repomd, cachedir, bootstrapdir):
-    cfgmgr = configmgr
-    lvl = msger.get_loglevel()
-    msger.set_loglevel('quiet')
-    repo_rpmver = misc.get_rpmver_in_repo(repomd)
-    if not repo_rpmver:
-        msger.set_loglevel(lvl)
-        return (None, None)
-
-    # Check avaliable bootstrap
-    bootstrap_env = bootstrap.Bootstrap(homedir = bootstrapdir)
-    for bs in bootstrap_env.list():
-        if compare_rpmversion(repo_rpmver, bs['rpm']):
-            return (bs['name'], {})
-
-    for bsname, bsrepo in cfgmgr.bootstraps.items():
-        repolist = []
-        for repo in bsrepo.keys():
-            repolist.append(bsrepo[repo])
-
-        rpmver = None
-        try:
-            repomd = misc.get_metadata_from_repos(repolist, cachedir)
-            rpmver = misc.get_rpmver_in_repo(repomd)
-        except errors.CreatorError, e:
-            msger.set_loglevel(lvl)
-            raise
-
-        if not rpmver:
-            continue
-        if compare_rpmversion(repo_rpmver, rpmver):
-            msger.set_loglevel(lvl)
-            return (bsname, bsrepo)
-    msger.set_loglevel(lvl)
-    return (None, None)
-
-def runmic_in_bootstrap(name, argv, opts, ksfile, repolist):
-    bootstrap_env = bootstrap.Bootstrap(homedir = opts['bootstrapdir'])
-    bootstrap_lst = bootstrap_env.bootstraps
-    setattr(bootstrap_env, 'rootdir', name)
-    if not bootstrap_lst or not name in bootstrap_lst:
-        msger.info("Creating bootstrap %s under %s" % \
-                   (name, bootstrap_env.homedir))
-        bootstrap_env.create(name, repolist)
-
-    msger.info("Use bootstrap: %s" % bootstrap_env.rootdir)
-    # copy mic
-    msger.info("Sync native mic to bootstrap")
-    copy_mic(bootstrap_env.rootdir)
-
-    # bind mounts , opts['cachedir'], opts['tmpdir']
-    cwd = os.getcwd()
-    lst = [cwd, opts['outdir']]
-    if ksfile:
-        ksfp = os.path.abspath(os.path.expanduser(ksfile))
-        lst.append(os.path.dirname(ksfp))
-    if opts['logfile']:
-        logfile = os.path.abspath(os.path.expanduser(opts['logfile']))
-        lst.append(os.path.dirname(logfile))
-    if opts['local_pkgs_path']:
-        lppdir = os.path.abspath(os.path.expanduser(opts['local_pkgs_path']))
-        lst.append(lppdir)
+    # run mic in bootstrap
+    globalmounts = None
+    bindmounts = get_bindmounts(cropts)
+    try:
+        proxy.set_proxy_environ()
+        globalmounts = setup_chrootenv(rootdir, bindmounts)
+        subprocess.call(argv, preexec_fn=mychroot)
+    except (OSError, IOError), err:
+        raise errors.BootstrapError("Failed to run mic in bootstrap: %s" % err)
+    finally:
+        cleanup_chrootenv(rootdir, bindmounts, globalmounts)
+        proxy.unset_proxy_environ()
 
-    # TBD local repo
+    sys.exit(0)
 
-    # make unique and remain the original order
-    lst = sorted(set(lst), key=lst.index)
+def get_bindmounts(cropts):
+    binddirs =  [
+                  os.getcwd(),
+                  cropts['tmpdir'],
+                  cropts['cachedir'],
+                  cropts['outdir'],
+                  cropts['local_pkgs_path'],
+                ]
+    bindfiles = [
+                  cropts['logfile'],
+                  configmgr._ksconf,
+                ]
+
+    bindlist = map(expath, filter(None, binddirs))
+    bindlist += map(os.path.dirname, map(expath, filter(None, bindfiles)))
+    bindlist = sorted(set(bindlist))
+    bindmounts = ';'.join(bindlist)
+    return bindmounts
 
-    bindmounts = ';'.join(map(lambda p: os.path.abspath(os.path.expanduser(p)),
-                              lst))
 
-    msger.info("Start mic command in bootstrap")
-    bootstrap_env.run(name, argv, cwd, bindmounts)
+def get_mic_binpath():
+    try:
+        fp = find_binary_path('mic')
+    except:
+        raise errors.BootstrapError("Can't find mic binary in host OS")
+    return fp
 
 def get_mic_modpath():
     try:
         import mic
     except ImportError:
-        raise errors.BootstrapError('Can\'t find mic module in host OS.')
-    else:
-        path = os.path.abspath(mic.__file__)
-        return os.path.dirname(path)
-
-def get_mic_binpath():
-    # FIXME: please use mic.find_binary_path()
-    path = os.environ['PATH']
-    paths = string.split(path, os.pathsep)
-    for pth in paths:
-        fn = os.path.join(pth, 'mic')
-        if os.path.isfile(fn):
-            return fn
-
-    msger.warning("Can't find mic command")
-    # FIXME: how to handle unfound case?
+        raise errors.BootstrapError("Can't find mic module in host OS")
+    path = os.path.abspath(mic.__file__)
+    return os.path.dirname(path)
 
 def get_mic_libpath():
-    # so far mic lib path is hard coded
-    # TBD
+    # TBD: so far mic lib path is hard coded
     return "/usr/lib/mic"
 
 # the hard code path is prepared for bootstrap
-def copy_mic(bootstrap_pth, bin_pth = '/usr/bin', lib_pth='/usr/lib', \
-             pylib_pth = '/usr/lib/python2.7/site-packages'):
-    # copy python lib files
-    mic_pylib = get_mic_modpath()
-    bs_mic_pylib = bootstrap_pth + os.path.join(pylib_pth, 'mic')
-    if os.path.commonprefix([mic_pylib, bs_mic_pylib]) == mic_pylib:
-        raise errors.BootstrapError('Invalid Bootstrap: %s' % bootstrap_pth)
-    shutil.rmtree(bs_mic_pylib, ignore_errors = True)
-    shutil.copytree(mic_pylib, bs_mic_pylib)
-    clean_files(".*\.py[co]$", bs_mic_pylib)
-
-    # copy lib files
-    mic_libpth = get_mic_libpath()
-    bs_mic_libpth = bootstrap_pth + os.path.join(lib_pth, 'mic')
-    if os.path.commonprefix([mic_libpth, bs_mic_libpth]) == mic_libpth:
-        raise errors.BootstrapError('Invalid Bootstrap: %s' % bootstrap_pth)
-    shutil.rmtree(bs_mic_libpth, ignore_errors = True)
-    shutil.copytree(mic_libpth, bs_mic_libpth)
-    os.system('cp -af %s %s' % (mic_libpth, os.path.dirname(bs_mic_libpth)))
-
-    # copy bin files
-    mic_binpth = get_mic_binpath()
-    bs_mic_binpth = bootstrap_pth + os.path.join(bin_pth, 'mic')
-    shutil.rmtree(bs_mic_binpth, ignore_errors = True)
-    shutil.copy2(mic_binpth, bs_mic_binpth)
-
-    # copy mic.conf
-    mic_cfgpth = '/etc/mic/mic.conf'
-    bs_mic_cfgpth = bootstrap_pth + mic_cfgpth
-    if not os.path.exists(os.path.dirname(bs_mic_cfgpth)):
-        os.makedirs(os.path.dirname(bs_mic_cfgpth))
-    shutil.copy2(mic_cfgpth, bs_mic_cfgpth)
-
-    # remove yum backend
-    try:
-        yumpth = "/usr/lib/mic/plugins/backend/yumpkgmgr.py"
-        os.unlink(bootstrap_pth + yumpth)
-    except:
-        pass
+def sync_mic(bootstrap, binpth = '/usr/bin/mic', libpth='/usr/lib/mic', \
+             pylib = '/usr/lib/python2.7/site-packages/mic',
+             conf = '/etc/mic/mic.conf'):
+    _path = lambda p: os.path.join(bootstrap, p.lstrip('/'))
+
+    micpaths = {
+                 'binpth': get_mic_binpath(),
+                 'libpth': get_mic_libpath(),
+                 'pylib': get_mic_modpath(),
+                 'conf': '/etc/mic/mic.conf',
+               }
+
+    for key, value in micpaths.items():
+        safecopy(value, _path(eval(key)))
+
+    # clean stuff:
+    # yum backend, not available in bootstrap;
+    # bootstrap.conf, disable bootstrap mode inside bootstrap
+    clrpaths = [os.path.join(libpth, 'plugins/backend/yumpkgmgr.py'),
+                os.path.join(libpth, 'plugins/backend/yumpkgmgr.pyc'),
+                '/etc/mic/bootstrap.conf',
+               ]
+
+    for pth in clrpaths:
+        try:
+            os.unlink(_path(pth)) 
+        except:
+            pass
+
+    # use default zypp backend
+    conf_str = file(_path(conf)).read()
+    conf_str = re.sub("pkgmgr\s*=\s*yum", "pkgmgr=zypp", conf_str)
+    with open(_path(conf), 'w') as wf:
+        wf.write(conf_str)
+
+def safecopy(src, dst, override=True):
+    if os.path.exists(dst):
+        os.system('rm -rf %s' % dst)
+    else:
+        os.system('mkdir -p %s' % os.path.dirname(dst))
+    os.system('cp -af %s %s' % (src, dst))
 
-def clean_files(pattern, dir):
-    if not os.path.exists(dir):
-        return
-    for f in os.listdir(dir):
-        entry = os.path.join(dir, f)
-        if os.path.isdir(entry):
-            clean_files(pattern, entry)
-        elif re.match(pattern, entry):
-            os.unlink(entry)