add more packages for tizen bootstrap
[platform/upstream/mic.git] / mic / bootstrap.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 tempfile
22 import shutil
23 import subprocess
24 import rpm
25 from mic import msger
26 from mic.utils import errors, proxy, misc
27 from mic.utils.rpmmisc import readRpmHeader, RPMInstallCallback
28 from mic.chroot import cleanup_mounts, setup_chrootenv, cleanup_chrootenv
29
30 RPMTRANS_FLAGS = [
31                    rpm.RPMTRANS_FLAG_ALLFILES,
32                    rpm.RPMTRANS_FLAG_NOSCRIPTS,
33                    rpm.RPMTRANS_FLAG_NOTRIGGERS,
34                  ]
35
36 RPMVSF_FLAGS = [
37                  rpm._RPMVSF_NOSIGNATURES,
38                  rpm._RPMVSF_NODIGESTS
39                ]
40
41 class MiniBackend(object):
42     def __init__(self, rootdir, arch=None, repomd=None):
43         self._ts = None
44         self.rootdir = os.path.abspath(rootdir)
45         self.arch = arch
46         self.repomd = repomd
47         self.dlpkgs = []
48         self.localpkgs = {}
49         self.preins = {}
50         self.postins = {}
51
52     def __del__(self):
53         try:
54             del self.ts
55         except:
56             pass
57
58     def get_ts(self):
59         if not self._ts:
60             self._ts = rpm.TransactionSet(self.rootdir)
61             self._ts.setFlags(reduce(lambda x, y: x|y, RPMTRANS_FLAGS))
62             self._ts.setVSFlags(reduce(lambda x, y: x|y, RPMVSF_FLAGS))
63         return self._ts
64
65     def del_ts(self):
66         if self._ts:
67             self._ts.closeDB()
68             self._ts = None
69
70     ts = property(fget = lambda self: self.get_ts(),
71                   fdel = lambda self: self.del_ts(),
72                   doc="TransactionSet object")
73
74     def selectPackage(self, pkg):
75         if not pkg in self.dlpkgs:
76             self.dlpkgs.append(pkg)
77
78     def runInstall(self):
79         # FIXME: check space
80         self.downloadPkgs()
81         self.installPkgs()
82
83         for pkg in self.preins.keys():
84             prog, script = self.preins[pkg]
85             self.run_pkg_script(pkg, prog, script, '0')
86         for pkg in self.postins.keys():
87             prog, script = self.postins[pkg]
88             self.run_pkg_script(pkg, prog, script, '1')
89
90     def downloadPkgs(self):
91         nonexist = []
92         for pkg in self.dlpkgs:
93             try:
94                 localpth = misc.get_package(pkg, self.repomd, self.arch)
95                 if not localpth:
96                     # skip non-existent rpm
97                     nonexist.append(pkg)
98                     continue
99                 self.localpkgs[pkg] = localpth
100             except:
101                 raise
102
103         if nonexist:
104             raise errors.BootstrapError("Can't get rpm binary: %s" %
105                                         ','.join(nonexist))
106
107     def installPkgs(self):
108         for pkg in self.localpkgs.keys():
109             rpmpath = self.localpkgs[pkg]
110
111             hdr = readRpmHeader(self.ts, rpmpath)
112
113             # save prein and postin scripts
114             self.preins[pkg] = (hdr['PREINPROG'], hdr['PREIN'])
115             self.postins[pkg] = (hdr['POSTINPROG'], hdr['POSTIN'])
116
117             # mark pkg as install
118             self.ts.addInstall(hdr, rpmpath, 'u')
119
120         # run transaction
121         self.ts.order()
122         cb = RPMInstallCallback(self.ts)
123         self.ts.run(cb.callback, '')
124
125     def run_pkg_script(self, pkg, prog, script, arg):
126         mychroot = lambda: os.chroot(self.rootdir)
127
128         if not script:
129             return
130
131         if prog == "<lua>":
132              prog = "/usr/bin/lua"
133
134         tmpdir = os.path.join(self.rootdir, "tmp")
135         if not os.path.exists(tmpdir):
136             os.makedirs(tmpdir)
137         tmpfd, tmpfp = tempfile.mkstemp(dir=tmpdir, prefix="%s.pre-" % pkg)
138         script = script.replace('\r', '')
139         os.write(tmpfd, script)
140         os.close(tmpfd)
141         os.chmod(tmpfp, 0700)
142
143         try:
144             script_fp = os.path.join('/tmp', os.path.basename(tmpfp))
145             subprocess.call([prog, script_fp, arg], preexec_fn=mychroot)
146         except (OSError, IOError), err:
147             msger.warning(str(err))
148         finally:
149             os.unlink(tmpfp)
150
151 class Bootstrap(object):
152     def __init__(self, rootdir, distro, arch=None):
153         self.rootdir = rootdir
154         self.distro = distro
155         self.arch = arch
156         self.logfile = None
157         self.pkgslist = []
158         self.repomd = None
159
160     def __del__(self):
161         self.cleanup()
162
163     def get_rootdir(self):
164         if os.path.exists(self.rootdir):
165             shutil.rmtree(self.rootdir, ignore_errors=True)
166         os.makedirs(self.rootdir)
167         return self.rootdir
168
169     def _path(self, pth):
170         return os.path.join(self.rootdir, pth.lstrip('/'))
171
172     def create(self, repomd, pkglist):
173         try:
174             pkgmgr = MiniBackend(self.get_rootdir())
175             pkgmgr.arch = self.arch
176             pkgmgr.repomd = repomd
177             map(pkgmgr.selectPackage, pkglist)
178             pkgmgr.runInstall()
179
180             # make /tmp path
181             tmpdir = self._path('/tmp')
182             if not os.path.exists(tmpdir):
183                 os.makedirs(tmpdir)
184
185             # touch distro file
186             tzdist = self._path('/etc/%s-release' % self.distro)
187             if not os.path.exists(tzdist):
188                 with open(tzdist, 'w') as wf:
189                     wf.write("bootstrap")
190
191         except (OSError, IOError, errors.CreatorError), err:
192             raise errors.BootstrapError("%s" % err)
193
194     def run(self, cmd, chdir, bindmounts=None):
195         def mychroot():
196             os.chroot(self.rootdir)
197             os.chdir(chdir)
198
199         if isinstance(cmd, list):
200             shell = False
201         else:
202             shell = True
203
204         retcode = 0
205         gloablmounts = None
206         try:
207             proxy.set_proxy_environ()
208             gloablmounts = setup_chrootenv(self.rootdir, bindmounts)
209             retcode = subprocess.call(cmd, preexec_fn = mychroot, shell=shell)
210         except (OSError, IOError), err:
211             raise RuntimeError(err)
212         finally:
213             if self.logfile:
214                 msger.log(file(self.logfile).read())
215             cleanup_chrootenv(self.rootdir, bindmounts, gloablmounts)
216             proxy.unset_proxy_environ()
217         return retcode
218
219     def cleanup(self):
220         try:
221             # clean mounts
222             cleanup_mounts(self.rootdir)
223             # remove rootdir
224             shutil.rmtree(self.rootdir, ignore_errors=True)
225         except:
226             pass