f5382711274c0f058055586aad9a7e8dadc5478a
[tools/mic.git] / mic / rt_util.py
1 #!/usr/bin/python -tt
2 #
3 # Copyright (c) 2009, 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
18 from __future__ import with_statement
19 import os
20 import sys
21 import glob
22 import re
23 import shutil
24 import subprocess
25
26 from mic import bootstrap, msger
27 from mic.conf import configmgr
28 from mic.utils import errors, proxy
29 from mic.utils.fs_related import find_binary_path, makedirs
30 from mic.chroot import setup_chrootenv, cleanup_chrootenv
31
32 expath = lambda p: os.path.abspath(os.path.expanduser(p))
33
34 def bootstrap_mic(argv=None):
35
36
37     def mychroot():
38         os.chroot(rootdir)
39         os.chdir(cwd)
40
41     # by default, sys.argv is used to run mic in bootstrap
42     if not argv:
43         argv = sys.argv
44     if argv[0] not in ('/usr/bin/mic', 'mic'):
45         argv[0] = '/usr/bin/mic'
46
47     cropts = configmgr.create
48     bsopts = configmgr.bootstrap
49     distro = bsopts['distro_name'].lower()
50     if distro not in bsopts:
51         msger.info("Use native running for distro don't support bootstrap")
52         return
53
54     rootdir = bsopts['rootdir']
55     pkglist = bsopts[distro]
56     cwd = os.getcwd()
57
58     # create bootstrap and run mic in bootstrap
59     bsenv = bootstrap.Bootstrap(rootdir, distro, cropts['arch'])
60     bsenv.logfile = cropts['logfile']
61     try:
62         msger.info("Creating %s bootstrap ..." % distro)
63         bsenv.create(cropts['repomd'], pkglist)
64         sync_mic(rootdir)
65
66         msger.info("Start mic in bootstrap: %s\n" % rootdir)
67         bindmounts = get_bindmounts(cropts)
68         ret = bsenv.run(argv, cwd, bindmounts)
69
70     except errors.BootstrapError, err:
71         msger.warning('\n%s' % err)
72         if msger.ask("Switch to native mode and continue?"):
73             return
74         else:
75             raise errors.BootstrapError("Failed to create bootstrap: %s" % err)
76     except RuntimeError, err:
77         raise errors.BootstrapError("Failed to run in bootstrap: %s" % err)
78     else:
79         sys.exit(ret)
80     finally:
81         bsenv.cleanup()
82
83 def get_bindmounts(cropts):
84     binddirs =  [
85                   os.getcwd(),
86                   cropts['tmpdir'],
87                   cropts['cachedir'],
88                   cropts['outdir'],
89                   cropts['local_pkgs_path'],
90                 ]
91     bindfiles = [
92                   cropts['logfile'],
93                   configmgr._ksconf,
94                 ]
95
96     bindlist = map(expath, filter(None, binddirs))
97     bindlist += map(os.path.dirname, map(expath, filter(None, bindfiles)))
98     bindlist = sorted(set(bindlist))
99     bindmounts = ';'.join(bindlist)
100     return bindmounts
101
102
103 def get_mic_binpath():
104     try:
105         fp = find_binary_path('mic')
106     except:
107         raise errors.BootstrapError("Can't find mic binary in host OS")
108     return fp
109
110 def get_mic_modpath():
111     try:
112         import mic
113     except ImportError:
114         raise errors.BootstrapError("Can't find mic module in host OS")
115     path = os.path.abspath(mic.__file__)
116     return os.path.dirname(path)
117
118 def get_mic_libpath():
119     # TBD: so far mic lib path is hard coded
120     return "/usr/lib/mic"
121
122 # the hard code path is prepared for bootstrap
123 def sync_mic(bootstrap, binpth = '/usr/bin/mic',
124              libpth='/usr/lib',
125              pylib = '/usr/lib/python2.7/site-packages',
126              conf = '/etc/mic/mic.conf'):
127     _path = lambda p: os.path.join(bootstrap, p.lstrip('/'))
128
129     micpaths = {
130                  'binpth': get_mic_binpath(),
131                  'libpth': get_mic_libpath(),
132                  'pylib': get_mic_modpath(),
133                  'conf': '/etc/mic/mic.conf',
134                }
135
136     if not os.path.exists(_path(pylib)):
137         pyptn = '/usr/lib/python?.?/site-packages'
138         pylibs = glob.glob(_path(pyptn))
139         if pylibs:
140             pylib = pylibs[0].replace(bootstrap, '')
141         else:
142             raise errors.BootstrapError("Can't find python site dir in: %s" %
143                                         bootstrap)
144
145     for key, value in micpaths.items():
146         try:
147             safecopy(value, _path(eval(key)), False, ["*.pyc", "*.pyo"])
148         except (OSError, IOError), err:
149             raise errors.BootstrapError(err)
150
151     # clean stuff:
152     # yum backend, not available in bootstrap;
153     # bootstrap.conf, disable bootstrap mode inside bootstrap
154     clrpaths = [os.path.join(libpth, 'plugins/backend/yumpkgmgr.py'),
155                 os.path.join(libpth, 'plugins/backend/yumpkgmgr.pyc'),
156                 '/etc/mic/bootstrap.conf',
157                ]
158
159     for pth in clrpaths:
160         try:
161             os.unlink(_path(pth)) 
162         except:
163             pass
164
165     # use default zypp backend
166     conf_str = file(_path(conf)).read()
167     conf_str = re.sub("pkgmgr\s*=\s*yum", "pkgmgr=zypp", conf_str)
168     with open(_path(conf), 'w') as wf:
169         wf.write(conf_str)
170
171     # correct python interpreter
172     mic_cont = file(_path(binpth)).read()
173     mic_cont = "#!/usr/bin/python\n" + mic_cont
174     with open(_path(binpth), 'w') as wf:
175         wf.write(mic_cont)
176
177 def safecopy(src, dst, symlinks=False, ignore_ptns=[]):
178     if os.path.isdir(src):
179         if os.path.isdir(dst):
180             dst = os.path.join(dst, os.path.basename(src))
181         if os.path.exists(dst):
182             shutil.rmtree(dst, ignore_errors=True)
183
184         src = src.rstrip('/')
185         # check common prefix to ignore copying itself
186         if dst.startswith(src + '/'):
187             ignore_ptns += os.path.basename(src)
188
189         try:
190             ignores = shutil.ignore_patterns(*ignore_ptns)
191             shutil.copytree(src, dst, symlinks, ignores)
192         except OSError, IOError:
193             shutil.rmtree(dst, ignore_errors=True)
194             raise
195
196     else:
197         try:
198             if not os.path.isdir(dst):
199                 makedirs(os.path.dirname(dst))
200
201             shutil.copy2(src, dst)
202         except:
203             raise