auto selecting backend with 'pkgmgr=auto'
[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     # bootstrap.conf, disable bootstrap mode inside bootstrap
153     clrpaths = [
154                 '/etc/mic/bootstrap.conf',
155                ]
156
157     for pth in clrpaths:
158         try:
159             os.unlink(_path(pth)) 
160         except:
161             pass
162
163     # auto select backend
164     conf_str = file(_path(conf)).read()
165     conf_str = re.sub("pkgmgr\s*=\s*.*", "pkgmgr=auto", conf_str)
166     with open(_path(conf), 'w') as wf:
167         wf.write(conf_str)
168
169     # correct python interpreter
170     mic_cont = file(_path(binpth)).read()
171     mic_cont = "#!/usr/bin/python\n" + mic_cont
172     with open(_path(binpth), 'w') as wf:
173         wf.write(mic_cont)
174
175 def safecopy(src, dst, symlinks=False, ignore_ptns=[]):
176     if os.path.isdir(src):
177         if os.path.isdir(dst):
178             dst = os.path.join(dst, os.path.basename(src))
179         if os.path.exists(dst):
180             shutil.rmtree(dst, ignore_errors=True)
181
182         src = src.rstrip('/')
183         # check common prefix to ignore copying itself
184         if dst.startswith(src + '/'):
185             ignore_ptns += os.path.basename(src)
186
187         try:
188             ignores = shutil.ignore_patterns(*ignore_ptns)
189             shutil.copytree(src, dst, symlinks, ignores)
190         except OSError, IOError:
191             shutil.rmtree(dst, ignore_errors=True)
192             raise
193
194     else:
195         try:
196             if not os.path.isdir(dst):
197                 makedirs(os.path.dirname(dst))
198
199             shutil.copy2(src, dst)
200         except:
201             raise