# 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)