224 lines
6.7 KiB
Python
224 lines
6.7 KiB
Python
#!/usr/bin/python -tt
|
|
#
|
|
# Copyright (c) 2009, 2010, 2011 Intel, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by the Free
|
|
# Software Foundation; version 2 of the License
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
# for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# 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 glob
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
|
|
from mic import bootstrap, msger
|
|
from mic.conf import configmgr
|
|
from mic.utils import errors, proxy
|
|
from mic.utils.fs_related import find_binary_path, makedirs
|
|
from mic.chroot import setup_chrootenv, cleanup_chrootenv
|
|
|
|
expath = lambda p: os.path.abspath(os.path.expanduser(p))
|
|
|
|
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
|
|
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()
|
|
|
|
rootdir = bsopts['rootdir']
|
|
pkglist = bsopts['packages']
|
|
cwd = os.getcwd()
|
|
|
|
# create bootstrap and run mic in bootstrap
|
|
bsenv = bootstrap.Bootstrap(rootdir, distro, cropts['arch'])
|
|
bsenv.logfile = cropts['logfile']
|
|
# rootdir is regenerated as a temp dir
|
|
rootdir = bsenv.rootdir
|
|
|
|
if 'optional' in bsopts:
|
|
optlist = bsopts['optional']
|
|
else:
|
|
optlist = []
|
|
|
|
try:
|
|
msger.info("Creating %s bootstrap ..." % distro)
|
|
bsenv.create(cropts['repomd'], pkglist, optlist)
|
|
|
|
# bootstrap is relocated under "bootstrap"
|
|
if os.path.exists(os.path.join(rootdir, "bootstrap")):
|
|
rootdir = os.path.join(rootdir, "bootstrap")
|
|
|
|
bsenv.dirsetup(rootdir)
|
|
sync_mic(rootdir)
|
|
|
|
#FIXME: sync the ks file to bootstrap
|
|
if "/" == os.path.dirname(os.path.abspath(configmgr._ksconf)):
|
|
safecopy(configmgr._ksconf, rootdir)
|
|
|
|
msger.info("Start mic in bootstrap: %s\n" % rootdir)
|
|
bindmounts = get_bindmounts(cropts)
|
|
ret = bsenv.run(argv, cwd, rootdir, bindmounts)
|
|
|
|
except errors.BootstrapError, err:
|
|
msger.warning('\n%s' % err)
|
|
if msger.ask("Switch to native mode and continue?"):
|
|
return
|
|
raise
|
|
except RuntimeError, err:
|
|
#change exception type but keep the trace back
|
|
value, tb = sys.exc_info()[1:]
|
|
raise errors.BootstrapError, value, tb
|
|
else:
|
|
sys.exit(ret)
|
|
finally:
|
|
bsenv.cleanup()
|
|
|
|
def get_bindmounts(cropts):
|
|
binddirs = [
|
|
os.getcwd(),
|
|
cropts['tmpdir'],
|
|
cropts['cachedir'],
|
|
cropts['outdir'],
|
|
cropts['local_pkgs_path'],
|
|
]
|
|
bindfiles = [
|
|
cropts['logfile'],
|
|
configmgr._ksconf,
|
|
]
|
|
|
|
for lrepo in cropts['localrepos']:
|
|
binddirs.append(lrepo)
|
|
|
|
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
|
|
|
|
|
|
def get_mic_binpath():
|
|
fp = None
|
|
try:
|
|
import pkg_resources # depends on 'setuptools'
|
|
except ImportError:
|
|
pass
|
|
else:
|
|
dist = pkg_resources.get_distribution('mic')
|
|
# the real script is under EGG_INFO/scripts
|
|
if dist.has_metadata('scripts/mic'):
|
|
fp = os.path.join(dist.egg_info, "scripts/mic")
|
|
|
|
if fp:
|
|
return fp
|
|
|
|
# not found script if 'flat' egg installed
|
|
try:
|
|
return find_binary_path('mic')
|
|
except errors.CreatorError:
|
|
raise errors.BootstrapError("Can't find mic binary in host OS")
|
|
|
|
|
|
def get_mic_modpath():
|
|
try:
|
|
import mic
|
|
except ImportError:
|
|
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():
|
|
# TBD: so far mic lib path is hard coded
|
|
return "/usr/lib/mic"
|
|
|
|
# the hard code path is prepared for bootstrap
|
|
def sync_mic(bootstrap, binpth = '/usr/bin/mic',
|
|
libpth='/usr/lib',
|
|
pylib = '/usr/lib/python2.7/site-packages',
|
|
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',
|
|
}
|
|
|
|
if not os.path.exists(_path(pylib)):
|
|
pyptn = '/usr/lib/python?.?/site-packages'
|
|
pylibs = glob.glob(_path(pyptn))
|
|
if pylibs:
|
|
pylib = pylibs[0].replace(bootstrap, '')
|
|
else:
|
|
raise errors.BootstrapError("Can't find python site dir in: %s" %
|
|
bootstrap)
|
|
|
|
for key, value in micpaths.items():
|
|
try:
|
|
safecopy(value, _path(eval(key)), False, ["*.pyc", "*.pyo"])
|
|
except (OSError, IOError), err:
|
|
raise errors.BootstrapError(err)
|
|
|
|
# auto select backend
|
|
conf_str = file(_path(conf)).read()
|
|
conf_str = re.sub("pkgmgr\s*=\s*.*", "pkgmgr=auto", conf_str)
|
|
with open(_path(conf), 'w') as wf:
|
|
wf.write(conf_str)
|
|
|
|
# chmod +x /usr/bin/mic
|
|
os.chmod(_path(binpth), 0777)
|
|
|
|
# correct python interpreter
|
|
mic_cont = file(_path(binpth)).read()
|
|
mic_cont = "#!/usr/bin/python\n" + mic_cont
|
|
with open(_path(binpth), 'w') as wf:
|
|
wf.write(mic_cont)
|
|
|
|
|
|
def safecopy(src, dst, symlinks=False, ignore_ptns=()):
|
|
if os.path.isdir(src):
|
|
if os.path.isdir(dst):
|
|
dst = os.path.join(dst, os.path.basename(src))
|
|
if os.path.exists(dst):
|
|
shutil.rmtree(dst, ignore_errors=True)
|
|
|
|
src = src.rstrip('/')
|
|
# check common prefix to ignore copying itself
|
|
if dst.startswith(src + '/'):
|
|
ignore_ptns = list(ignore_ptns) + [ os.path.basename(src) ]
|
|
|
|
ignores = shutil.ignore_patterns(*ignore_ptns)
|
|
try:
|
|
shutil.copytree(src, dst, symlinks, ignores)
|
|
except (OSError, IOError):
|
|
shutil.rmtree(dst, ignore_errors=True)
|
|
raise
|
|
else:
|
|
if not os.path.isdir(dst):
|
|
makedirs(os.path.dirname(dst))
|
|
|
|
shutil.copy2(src, dst)
|