Patch for Bug #227013 - /boot not mounted
[moblin-image-creator.eeepc.git] / libs / Platform.py
blobd74c386a7b1194a094b30f7fd78182dcc9dcafe9
1 #!/usr/bin/python -tt
2 # vim: ai ts=4 sts=4 et sw=4
4 # Copyright (c) 2007 Intel Corporation
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; version 2 of the License
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 # for more details.
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc., 59
17 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 import ConfigParser
20 import gettext
21 import os
22 import re
23 import shutil
24 import stat
25 import sys
26 import time
28 import fsets
29 import mic_cfg
30 import moblin_pkg
31 import pdk_utils
33 _ = gettext.lgettext
35 class Platform(object):
36 """
37 The SDK is composed of a collection of platforms, where this class
38 represents a specific platform. A platform provides:
39 - a list of packages to install directly into the platform (i.e. to use as
40 a jailroot to isolate building target binaries from the host
41 distribution)
42 - a set of fsets that can be installed into a target
43 """
44 def __init__(self, platform_path, platform_name, config_info = None):
45 self.name = platform_name
46 self.path = platform_path
47 if config_info != None:
48 self.config_info = {}
49 for key, value in sorted(config_info):
50 self.config_info[key] = value
51 else:
52 raise ValueError(_("Platform called but config_info value not passed in"))
53 # instantiate all fsets
54 self.fset = fsets.FSet()
55 fset_path = os.path.join(self.path, 'fsets')
56 for filename in os.listdir(fset_path):
57 # Only load files which end with the .fset extension
58 if not filename.endswith('.fset'):
59 continue
60 full_path = os.path.join(fset_path, filename)
61 self.fset.addFile(full_path)
62 local_config = []
63 for section in [ "platform.%s" % self.name, "platform" ]:
64 if mic_cfg.config.has_section(section):
65 # section is now set to the appropriate section
66 break
67 else:
68 print _("Error: No buildroot config file information found!")
69 raise ValueError
71 # determine what packages additional packages need to be installed
72 # in the buildroot roostrap
73 packages = mic_cfg.config.get(section, "buildroot_extras")
74 self.buildroot_extras = packages.split()
75 # determine what packages need to be installed in the buildroot
76 # (outside the rootstrap archive)
77 packages = mic_cfg.config.get(section, "buildroot_packages")
78 self.buildroot_packages = packages.split()
79 # determine what mirror to use for the buildroot
80 self.buildroot_mirror = mic_cfg.config.get(section, "buildroot_mirror")
81 # determine what codename to use for the buildroot mirror
82 self.buildroot_codename = mic_cfg.config.get(section, "buildroot_codename")
83 # determine what components to use for the buildroot mirror
84 components = mic_cfg.config.get(section, "buildroot_components")
85 self.buildroot_components = components.split()
86 # determine default kernel cmdline options
87 self.usb_kernel_cmdline = mic_cfg.config.get(section, "usb_kernel_cmdline")
88 self.hd_kernel_cmdline = mic_cfg.config.get(section, "hd_kernel_cmdline")
89 self.cd_kernel_cmdline = mic_cfg.config.get(section, "cd_kernel_cmdline")
90 # Architecture
91 self.architecture = mic_cfg.config.get(section, "architecture") or "i386"
92 # Package Manager
93 if self.config_info['package_manager'] == 'apt':
94 self.pkg_manager = moblin_pkg.AptPackageManager()
95 self.createChroot = self.aptCreateChroot
96 elif self.config_info['package_manager'] == 'yum':
97 self.pkg_manager = moblin_pkg.YumPackageManager()
98 self.createChroot = self.yumCreateChroot
99 else:
100 raise ValueError(_("package manager value of: '%s' is invalid") % self.config_info['package_manager'])
101 # Target OS
102 self.target_os = self.config_info['target_os']
104 def __str__(self):
105 return ("<Platform Object: \n\tname=%s, \n\tfset=%s, \n\tbuildroot_packages=%s>\n" %
106 (self.name, self.fset, self.buildroot_packages))
108 def __repr__(self):
109 return "Platform( %s, '%s')" % (self.path, self.name)
111 def __createRootstrap(self, chroot_dir, rootstrap_file, callback = None):
112 cmd = "tar -jcpvf %s -C %s ." % (rootstrap_file, chroot_dir)
113 output = []
114 result = pdk_utils.execCommand(cmd, output = output, callback = callback)
115 if result != 0:
116 print >> sys.stderr, _("ERROR: Unable to archive rootstrap!")
117 pdk_utils.rmtree(chroot_dir, callback = callback)
118 # FIXME: Better exception here
119 raise ValueError(" ".join(output))
121 def aptCreateChroot(self, chroot_dir, use_rootstrap, callback = None):
122 """Create chroot in chroot_dir for using APT tools"""
123 if not os.path.exists(chroot_dir):
124 os.makedirs(chroot_dir)
125 target_os = self.target_os
126 var_dir = mic_cfg.config.get('general', 'var_dir')
127 rootstrap_file = os.path.join(var_dir, "rootstraps", "apt", target_os, self.name, "rootstrap.tgz")
128 if not os.path.exists(rootstrap_file):
129 if self.__aptCreateRootstrap(chroot_dir, rootstrap_file, use_rootstrap, callback = callback) == False:
130 return False
131 else:
132 cmd = "tar -jxvf %s -C %s" % (rootstrap_file, chroot_dir)
133 output = []
134 result = pdk_utils.execCommand(cmd, output = output, callback = callback)
135 if result != 0:
136 print >> sys.stderr, _("ERROR: Unable to rootstrap %s from %s!") % (rootstrap_file, self.name)
137 pdk_utils.rmtree(chroot_dir, callback = callback)
138 # FIXME: Better exception here
139 raise ValueError(" ".join(output))
140 # Setup copies of some useful files from the host into the chroot
141 for filename in [ 'hosts', 'resolv.conf' ]:
142 source_file = os.path.join("/etc", filename)
143 target_file = os.path.join(chroot_dir, 'etc', filename)
144 pdk_utils.safeTextFileCopy(source_file, target_file, force = True)
145 return True
147 def __aptCreateRootstrap(self, chroot_dir, rootstrap_file, use_rootstrap, callback = None):
148 codename = self.buildroot_codename
149 components = ",".join(self.buildroot_components)
150 mirror = self.buildroot_mirror
151 chroot_type_string = "Platform"
152 basedir = os.path.dirname(rootstrap_file)
153 if not os.path.exists(basedir):
154 os.makedirs(basedir)
155 cmd = "debootstrap --arch %s --include=apt --components=%s %s %s %s" % (self.architecture, components, codename, chroot_dir, mirror)
156 output = []
157 # XXX Evil hack
158 if not os.path.isfile("/usr/lib/debootstrap/scripts/%s" % codename) and not os.path.isfile("/usr/share/debootstrap/scripts/%s" % codename):
159 cmd += " /usr/share/pdk/debootstrap-scripts/%s" % codename
160 # Sometimes we see network issues that trigger debootstrap to claim the
161 # apt repository is corrupt. This trick will force up to 10 attempts
162 # before bailing out with an error
163 count = 0
164 while count < 10:
165 count += 1
166 print _("--------%s rootstrap creation try: %s ----------") % (chroot_type_string, count)
167 print _("Execing command: %s") % cmd
168 result = pdk_utils.execCommand(cmd, output = output, callback = callback)
169 if result == 0:
170 print _("--------%s rootstrap creation completed successfully----------") % chroot_type_string
171 break;
172 if result < 0:
173 print _("Process Aborted")
174 return False
175 print _("--------%s rootstrap creation failed result: %s ----------") % (chroot_type_string, result)
176 sleeptime = 30
177 print _("--------For try: %s. Sleeping for %s seconds... -----------------") % (count, sleeptime)
178 time.sleep(sleeptime)
179 if result != 0:
180 print >> sys.stderr, _("ERROR: Unable to generate %s rootstrap!") % chroot_type_string
181 raise ValueError(" ".join(output))
182 self.pkg_manager.cleanPackageCache(chroot_dir)
183 source_dir = os.path.join(self.path, 'sources')
184 for filename in os.listdir(source_dir):
185 source_path = os.path.join(source_dir, filename)
186 dest_path = os.path.join(chroot_dir, 'etc', 'apt', 'sources.list.d', filename)
187 pdk_utils.copySourcesListFile(source_path, dest_path)
188 source_path = os.path.join(self.path, 'preferences')
189 if os.path.exists(source_path):
190 shutil.copy(source_path, os.path.join(chroot_dir, 'etc', 'apt'))
191 if use_rootstrap == True:
192 self.__createRootstrap(chroot_dir, rootstrap_file, callback = None)
194 def yumCreateChroot(self, chroot_dir, use_rootstrap, callback = None):
195 if not os.path.exists(chroot_dir):
196 os.makedirs(chroot_dir)
197 target_os = self.target_os
198 var_dir = mic_cfg.config.get('general', 'var_dir')
199 rootstrap_file = os.path.join(var_dir, "rootstraps", "yum", target_os, "rootstrap.tgz")
200 if not os.path.exists(rootstrap_file):
201 self.__yumCreateRootstrap(chroot_dir, rootstrap_file, use_rootstrap, callback = callback)
202 else:
203 cmd = "tar -jxvf %s -C %s" % (rootstrap_file, chroot_dir)
204 output = []
205 result = pdk_utils.execCommand(cmd, output = output, callback = callback)
206 if result != 0:
207 print >> sys.stderr, _("ERROR: Unable to rootstrap %s from %s!") % (rootstrap_file, name)
208 pdk_utils.rmtree(chroot_dir, callback = callback)
209 # FIXME: Better exception here
210 raise ValueError(" ".join(output))
212 def __yumCreateRootstrap(self, chroot_dir, rootstrap_file, use_rootstrap, callback = None):
213 basedir = os.path.dirname(rootstrap_file)
214 if not os.path.exists(basedir):
215 os.makedirs(basedir)
216 self.__yumCreateBase(chroot_dir)
217 self.__yumCreateDevices(chroot_dir)
218 self.__yumDoMounts(chroot_dir)
219 # install yum inside the project using the host tools
220 print _("Creating rootstrap directory with yum...")
221 output = []
222 cmd = 'yum -y --disablerepo=localbase --installroot=%s install yum yum-protectbase' % chroot_dir
223 cmd = 'yum -y --installroot=%s install yum yum-protectbase' % chroot_dir
224 #cmd = 'yum -y --installroot=%s groupinstall buildsys-build' % chroot_dir
225 print _("Exec command: %s") % cmd
226 result = pdk_utils.execCommand(cmd, output = output, callback = callback)
227 if result != 0:
228 raise RuntimeError(_("Failed to create Yum based rootstrap"))
229 # nuke all the yum cache to ensure that we get the latest greatest at project creation
230 shutil.rmtree(os.path.join(chroot_dir, 'var', 'cache', 'yum'))
231 self.__yumDoUmounts(chroot_dir)
232 # Create the rootstrap archive file
233 if use_rootstrap == True:
234 self.__createRootstrap(chroot_dir, rootstrap_file, callback = callback)
236 def __yumDoMounts(self, chroot_dir):
237 for cmd in ['mount -n -t proc mic_chroot_proc %s/proc' % chroot_dir,
238 'mount -n -t devpts mic_chroot_devpts %s/dev/pts' % chroot_dir,
239 'mount -n -t sysfs mic_chroot_sysfs %s/sys' % chroot_dir,
241 pdk_utils.execCommand(cmd)
243 def __yumDoUmounts(self, chroot_dir):
244 pdk_utils.umountAllInPath(chroot_dir)
246 def __yumCreateBase(self, chroot_dir):
247 for dirname in [
248 'dev',
249 'dev/pts',
250 'etc/yum.repos.d',
251 'proc',
252 'var/lib/rpm',
253 'var/lib/yum',
254 'var/log',
255 'sys',
257 os.makedirs(os.path.join(chroot_dir, dirname))
258 target_etc = os.path.join(chroot_dir, "etc")
259 # Setup copies of some useful files from the host into the chroot
260 for filename in [ 'hosts', 'resolv.conf' ]:
261 source_file = os.path.join("/etc", filename)
262 target_file = os.path.join(target_etc, filename)
263 pdk_utils.safeTextFileCopy(source_file, target_file, force = True)
264 yumconf = open(os.path.join(target_etc, 'yum.conf'), 'w')
265 print >> yumconf, """\
266 [main]
267 cachedir=/var/cache/yum
268 keepcache=0
269 debuglevel=2
270 logfile=/var/log/yum.log
271 pkgpolicy=newest
272 distroverpkg=redhat-release
273 tolerant=1
274 exactarch=1
275 obsoletes=1
276 gpgcheck=0
277 plugins=1
278 metadata_expire=1800
279 releasever=8
281 yumconf.close()
282 yum_repos_dir = os.path.join(self.path, 'yum.repos.d')
283 for filename in os.listdir(yum_repos_dir):
284 source_path = os.path.join(yum_repos_dir, filename)
285 dest_path = os.path.join(chroot_dir, 'etc', 'yum.repos.d', filename)
286 pdk_utils.copySourcesListFile(source_path, dest_path)
288 def __yumCreateDevices(self, chroot_dir):
289 devices = [
290 # name, major, minor, mode
291 ('console', 5, 1, (0600 | stat.S_IFCHR)),
292 ('null', 1, 3, (0666 | stat.S_IFCHR)),
293 ('random', 1, 8, (0666 | stat.S_IFCHR)),
294 ('urandom', 1, 9, (0444 | stat.S_IFCHR)),
295 ('zero', 1, 5, (0666 | stat.S_IFCHR)),
297 for device_name, major, minor, mode in devices:
298 device_path = os.path.join(chroot_dir, 'dev', device_name)
299 device = os.makedev(major, minor)
300 os.mknod(device_path, mode, device)
301 # Seems redundant, but mknod doesn't seem to set the mode to
302 # what we want :(
303 os.chmod(device_path, mode)
305 def update(self, path):
306 command = '-y --installroot=%s update' % (path)
307 ret = self.chroot("/usr/bin/yum", command)
308 if ret != 0:
309 raise OSError(_("Internal error while attempting to run: %s") % command)
312 def install(self, path, packages):
314 Call into yum to install RPM packages using the specified yum
315 repositories
317 if not packages:
318 # No packages, so nothing to do
319 return
320 command = '-y --installroot=%s install ' % (path)
321 for p in packages:
322 command += ' %s' % p
323 ret = self.chroot("/usr/bin/yum", command)
324 if ret != 0:
325 raise OSError(_("Internal error while attempting to run: %s") % command)
328 if __name__ == '__main__':
329 for p in sys.argv[1:]:
330 print Platform('/usr/share/pdk', p)