1 import os,string,imp,types,shutil
2 from catalyst.support import *
3 from generic_target import *
5 from catalyst.lock import LockDir
9 'find "${PORT_LOGDIR}" -type f ! -name "summary.log*" -mtime +30 -delete'
11 TARGET_MOUNTS_DEFAULTS = {
12 "ccache": "/var/tmp/ccache",
15 "distdir": "/usr/portage/distfiles",
16 "icecream": "/usr/lib/icecc/bin",
17 "kerncache": "/tmp/kerncache",
18 "packagedir": "/usr/portage/packages",
19 "portdir": "/usr/portage",
20 "port_tmpdir": "/var/tmp/portage",
21 "port_logdir": "/var/log/portage",
26 SOURCE_MOUNTS_DEFAULTS = {
29 "distdir": "/usr/portage/distfiles",
30 "portdir": "/usr/portage",
31 "port_tmpdir": "tmpfs",
37 class generic_stage_target(generic_target):
39 This class does all of the chroot setup, copying of files, etc. It is
40 the driver class for pretty much everything that Catalyst does.
42 def __init__(self,myspec,addlargs):
43 self.required_values.extend(["version_stamp","target","subarch",\
44 "rel_type","profile","snapshot","source_subpath"])
46 self.valid_values.extend(["version_stamp","target","subarch",\
47 "rel_type","profile","snapshot","source_subpath","portage_confdir",\
48 "cflags","cxxflags","ldflags","cbuild","hostuse","portage_overlay",\
49 "distcc_hosts","makeopts","pkgcache_path","kerncache_path"])
51 self.set_valid_build_kernel_vars(addlargs)
52 generic_target.__init__(self,myspec,addlargs)
55 The semantics of subarchmap and machinemap changed a bit in 2.0.3 to
56 work better with vapier's CBUILD stuff. I've removed the "monolithic"
57 machinemap from this file and split up its contents amongst the
58 various arch/foo.py files.
60 When register() is called on each module in the arch/ dir, it now
61 returns a tuple instead of acting on the subarchmap dict that is
62 passed to it. The tuple contains the values that were previously
63 added to subarchmap as well as a new list of CHOSTs that go along
64 with that arch. This allows us to build machinemap on the fly based
65 on the keys in subarchmap and the values of the 2nd list returned
68 Also, after talking with vapier. I have a slightly better idea of what
69 certain variables are used for and what they should be set to. Neither
70 'buildarch' or 'hostarch' are used directly, so their value doesn't
71 really matter. They are just compared to determine if we are
72 cross-compiling. Because of this, they are just set to the name of the
73 module in arch/ that the subarch is part of to make things simpler.
74 The entire build process is still based off of 'subarch' like it was
81 arch_dir = self.settings["PythonDir"] + "/arch/"
82 for x in [x[:-3] for x in os.listdir(arch_dir) if x.endswith(".py")]:
86 fh=open(arch_dir + x + ".py")
88 This next line loads the plugin as a module and assigns it to
91 self.archmap[x]=imp.load_module(x,fh,"../arch/" + x + ".py",
92 (".py", "r", imp.PY_SOURCE))
94 This next line registers all the subarches supported in the
97 tmpsubarchmap, tmpmachinemap = self.archmap[x].register()
98 self.subarchmap.update(tmpsubarchmap)
99 for machine in tmpmachinemap:
100 machinemap[machine] = x
101 for subarch in tmpsubarchmap:
102 machinemap[subarch] = x
106 This message should probably change a bit, since everything in
107 the dir should load just fine. If it doesn't, it's probably a
108 syntax error in the module
110 msg("Can't find/load " + x + ".py plugin in " + arch_dir)
112 if "chost" in self.settings:
113 hostmachine = self.settings["chost"].split("-")[0]
114 if hostmachine not in machinemap:
115 raise CatalystError, "Unknown host machine type "+hostmachine
116 self.settings["hostarch"]=machinemap[hostmachine]
118 hostmachine = self.settings["subarch"]
119 if hostmachine in machinemap:
120 hostmachine = machinemap[hostmachine]
121 self.settings["hostarch"]=hostmachine
122 if "cbuild" in self.settings:
123 buildmachine = self.settings["cbuild"].split("-")[0]
125 buildmachine = os.uname()[4]
126 if buildmachine not in machinemap:
127 raise CatalystError, "Unknown build machine type "+buildmachine
128 self.settings["buildarch"]=machinemap[buildmachine]
129 self.settings["crosscompile"]=(self.settings["hostarch"]!=\
130 self.settings["buildarch"])
132 """ Call arch constructor, pass our settings """
134 self.arch=self.subarchmap[self.settings["subarch"]](self.settings)
136 print "Invalid subarch: "+self.settings["subarch"]
137 print "Choose one of the following:",
138 for x in self.subarchmap:
143 print "Using target:",self.settings["target"]
144 """ Print a nice informational message """
145 if self.settings["buildarch"]==self.settings["hostarch"]:
146 print "Building natively for",self.settings["hostarch"]
147 elif self.settings["crosscompile"]:
148 print "Cross-compiling on",self.settings["buildarch"],\
149 "for different machine type",self.settings["hostarch"]
151 print "Building on",self.settings["buildarch"],\
152 "for alternate personality type",self.settings["hostarch"]
154 """ This must be set first as other set_ options depend on this """
155 self.set_spec_prefix()
157 """ Define all of our core variables """
158 self.set_target_profile()
159 self.set_target_subpath()
160 self.set_source_subpath()
163 self.set_snapshot_path()
165 self.set_source_path()
166 self.set_snapcache_path()
167 self.set_chroot_path()
168 self.set_autoresume_path()
170 self.set_stage_path()
171 self.set_target_path()
173 self.set_controller_file()
174 self.set_action_sequence()
176 self.set_cleanables()
177 self.set_iso_volume_id()
178 self.set_build_kernel_vars()
180 self.set_install_mask()
190 self.set_busybox_config()
192 self.set_portage_overlay()
193 self.set_root_overlay()
196 This next line checks to make sure that the specified variables exist
200 file_locate(self.settings,["source_path","snapshot_path","distdir"],\
202 """ If we are using portage_confdir, check that as well. """
203 if "portage_confdir" in self.settings:
204 file_locate(self.settings,["portage_confdir"],expand=0)
206 """ Setup our mount points """
207 # initialize our target mounts.
208 self.target_mounts = TARGET_MOUNTS_DEFAULTS.copy()
210 self.mounts = ["proc", "dev", "portdir", "distdir", "port_tmpdir"]
211 # initialize our source mounts
212 self.mountmap = SOURCE_MOUNTS_DEFAULTS.copy()
213 # update them from settings
214 self.mountmap["distdir"] = self.settings["distdir"]
215 self.mountmap["portdir"] = normpath("/".join([
216 self.settings["snapshot_cache_path"],
217 self.settings["repo_name"],
219 if "SNAPCACHE" not in self.settings:
220 self.mounts.remove("portdir")
221 #self.mountmap["portdir"] = None
222 if os.uname()[0] == "Linux":
223 self.mounts.append("devpts")
224 self.mounts.append("shm")
229 Configure any user specified options (either in catalyst.conf or on
232 if "PKGCACHE" in self.settings:
233 self.set_pkgcache_path()
234 print "Location of the package cache is "+\
235 self.settings["pkgcache_path"]
236 self.mounts.append("packagedir")
237 self.mountmap["packagedir"] = self.settings["pkgcache_path"]
239 if "KERNCACHE" in self.settings:
240 self.set_kerncache_path()
241 print "Location of the kerncache is "+\
242 self.settings["kerncache_path"]
243 self.mounts.append("kerncache")
244 self.mountmap["kerncache"] = self.settings["kerncache_path"]
246 if "CCACHE" in self.settings:
247 if "CCACHE_DIR" in os.environ:
248 ccdir=os.environ["CCACHE_DIR"]
249 del os.environ["CCACHE_DIR"]
251 ccdir="/root/.ccache"
252 if not os.path.isdir(ccdir):
253 raise CatalystError,\
254 "Compiler cache support can't be enabled (can't find "+\
256 self.mounts.append("ccache")
257 self.mountmap["ccache"] = ccdir
258 """ for the chroot: """
259 self.env["CCACHE_DIR"] = self.target_mounts["ccache"]
261 if "ICECREAM" in self.settings:
262 self.mounts.append("icecream")
263 self.mountmap["icecream"] = self.settings["icecream"]
264 self.env["PATH"] = self.target_mounts["icecream"] + ":" + \
267 if "port_logdir" in self.settings:
268 self.mounts.append("port_logdir")
269 self.mountmap["port_logdir"] = self.settings["port_logdir"]
270 self.env["PORT_LOGDIR"] = self.settings["port_logdir"]
271 self.env["PORT_LOGDIR_CLEAN"] = PORT_LOGDIR_CLEAN
273 def override_cbuild(self):
274 if "CBUILD" in self.makeconf:
275 self.settings["CBUILD"]=self.makeconf["CBUILD"]
277 def override_chost(self):
278 if "CHOST" in self.makeconf:
279 self.settings["CHOST"]=self.makeconf["CHOST"]
281 def override_cflags(self):
282 if "CFLAGS" in self.makeconf:
283 self.settings["CFLAGS"]=self.makeconf["CFLAGS"]
285 def override_cxxflags(self):
286 if "CXXFLAGS" in self.makeconf:
287 self.settings["CXXFLAGS"]=self.makeconf["CXXFLAGS"]
289 def override_ldflags(self):
290 if "LDFLAGS" in self.makeconf:
291 self.settings["LDFLAGS"]=self.makeconf["LDFLAGS"]
293 def set_install_mask(self):
294 if "install_mask" in self.settings:
295 if type(self.settings["install_mask"])!=types.StringType:
296 self.settings["install_mask"]=\
297 string.join(self.settings["install_mask"])
299 def set_spec_prefix(self):
300 self.settings["spec_prefix"]=self.settings["target"]
302 def set_target_profile(self):
303 self.settings["target_profile"]=self.settings["profile"]
305 def set_target_subpath(self):
306 self.settings["target_subpath"]=self.settings["rel_type"]+"/"+\
307 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
308 self.settings["version_stamp"]
310 def set_source_subpath(self):
311 if type(self.settings["source_subpath"])!=types.StringType:
312 raise CatalystError,\
313 "source_subpath should have been a string. Perhaps you have something wrong in your spec file?"
315 def set_pkgcache_path(self):
316 if "pkgcache_path" in self.settings:
317 if type(self.settings["pkgcache_path"])!=types.StringType:
318 self.settings["pkgcache_path"]=\
319 normpath(string.join(self.settings["pkgcache_path"]))
321 self.settings["pkgcache_path"]=\
322 normpath(self.settings["storedir"]+"/packages/"+\
323 self.settings["target_subpath"]+"/")
325 def set_kerncache_path(self):
326 if "kerncache_path" in self.settings:
327 if type(self.settings["kerncache_path"])!=types.StringType:
328 self.settings["kerncache_path"]=\
329 normpath(string.join(self.settings["kerncache_path"]))
331 self.settings["kerncache_path"]=normpath(self.settings["storedir"]+\
332 "/kerncache/"+self.settings["target_subpath"]+"/")
334 def set_target_path(self):
335 self.settings["target_path"]=normpath(self.settings["storedir"]+\
336 "/builds/"+self.settings["target_subpath"]+".tar.bz2")
337 if "AUTORESUME" in self.settings\
338 and os.path.exists(self.settings["autoresume_path"]+\
339 "setup_target_path"):
341 "Resume point detected, skipping target path setup operation..."
343 """ First clean up any existing target stuff """
344 # XXX WTF are we removing the old tarball before we start building the
345 # XXX new one? If the build fails, you don't want to be left with
347 # if os.path.isfile(self.settings["target_path"]):
348 # cmd("rm -f "+self.settings["target_path"],\
349 # "Could not remove existing file: "\
350 # +self.settings["target_path"],env=self.env)
351 touch(self.settings["autoresume_path"]+"setup_target_path")
353 if not os.path.exists(self.settings["storedir"]+"/builds/"):
354 os.makedirs(self.settings["storedir"]+"/builds/")
356 def set_fsscript(self):
357 if self.settings["spec_prefix"]+"/fsscript" in self.settings:
358 self.settings["fsscript"]=\
359 self.settings[self.settings["spec_prefix"]+"/fsscript"]
360 del self.settings[self.settings["spec_prefix"]+"/fsscript"]
363 if self.settings["spec_prefix"]+"/rcadd" in self.settings:
364 self.settings["rcadd"]=\
365 self.settings[self.settings["spec_prefix"]+"/rcadd"]
366 del self.settings[self.settings["spec_prefix"]+"/rcadd"]
369 if self.settings["spec_prefix"]+"/rcdel" in self.settings:
370 self.settings["rcdel"]=\
371 self.settings[self.settings["spec_prefix"]+"/rcdel"]
372 del self.settings[self.settings["spec_prefix"]+"/rcdel"]
375 if self.settings["spec_prefix"]+"/cdtar" in self.settings:
376 self.settings["cdtar"]=\
377 normpath(self.settings[self.settings["spec_prefix"]+"/cdtar"])
378 del self.settings[self.settings["spec_prefix"]+"/cdtar"]
381 if self.settings["spec_prefix"]+"/iso" in self.settings:
382 if self.settings[self.settings["spec_prefix"]+"/iso"].startswith('/'):
383 self.settings["iso"]=\
384 normpath(self.settings[self.settings["spec_prefix"]+"/iso"])
386 # This automatically prepends the build dir to the ISO output path
387 # if it doesn't start with a /
388 self.settings["iso"] = normpath(self.settings["storedir"] + \
389 "/builds/" + self.settings["rel_type"] + "/" + \
390 self.settings[self.settings["spec_prefix"]+"/iso"])
391 del self.settings[self.settings["spec_prefix"]+"/iso"]
393 def set_fstype(self):
394 if self.settings["spec_prefix"]+"/fstype" in self.settings:
395 self.settings["fstype"]=\
396 self.settings[self.settings["spec_prefix"]+"/fstype"]
397 del self.settings[self.settings["spec_prefix"]+"/fstype"]
399 if "fstype" not in self.settings:
400 self.settings["fstype"]="normal"
401 for x in self.valid_values:
402 if x == self.settings["spec_prefix"]+"/fstype":
403 print "\n"+self.settings["spec_prefix"]+\
404 "/fstype is being set to the default of \"normal\"\n"
407 if "fstype" in self.settings:
408 self.valid_values.append("fsops")
409 if self.settings["spec_prefix"]+"/fsops" in self.settings:
410 self.settings["fsops"]=\
411 self.settings[self.settings["spec_prefix"]+"/fsops"]
412 del self.settings[self.settings["spec_prefix"]+"/fsops"]
414 def set_source_path(self):
415 if "SEEDCACHE" in self.settings\
416 and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+\
417 self.settings["source_subpath"]+"/")):
418 self.settings["source_path"]=normpath(self.settings["storedir"]+\
419 "/tmp/"+self.settings["source_subpath"]+"/")
421 self.settings["source_path"]=normpath(self.settings["storedir"]+\
422 "/builds/"+self.settings["source_subpath"]+".tar.bz2")
423 if os.path.isfile(self.settings["source_path"]):
424 # XXX: Is this even necessary if the previous check passes?
425 if os.path.exists(self.settings["source_path"]):
426 self.settings["source_path_hash"]=\
427 generate_hash(self.settings["source_path"],\
428 hash_function=self.settings["hash_function"],\
430 print "Source path set to "+self.settings["source_path"]
431 if os.path.isdir(self.settings["source_path"]):
432 print "\tIf this is not desired, remove this directory or turn off"
433 print "\tseedcache in the options of catalyst.conf the source path"
434 print "\twill then be "+\
435 normpath(self.settings["storedir"]+"/builds/"+\
436 self.settings["source_subpath"]+".tar.bz2\n")
438 def set_dest_path(self):
439 if "root_path" in self.settings:
440 self.settings["destpath"]=normpath(self.settings["chroot_path"]+\
441 self.settings["root_path"])
443 self.settings["destpath"]=normpath(self.settings["chroot_path"])
445 def set_cleanables(self):
446 self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/tmp/*",\
447 "/root/*", self.settings["portdir"]]
449 def set_snapshot_path(self):
450 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
451 "/snapshots/" + self.settings["snapshot_name"] +
452 self.settings["snapshot"] + ".tar.xz")
454 if os.path.exists(self.settings["snapshot_path"]):
455 self.settings["snapshot_path_hash"]=\
456 generate_hash(self.settings["snapshot_path"],\
457 hash_function=self.settings["hash_function"],verbose=False)
459 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
460 "/snapshots/" + self.settings["snapshot_name"] +
461 self.settings["snapshot"] + ".tar.bz2")
463 if os.path.exists(self.settings["snapshot_path"]):
464 self.settings["snapshot_path_hash"]=\
465 generate_hash(self.settings["snapshot_path"],\
466 hash_function=self.settings["hash_function"],verbose=False)
468 def set_snapcache_path(self):
469 if "SNAPCACHE" in self.settings:
470 self.settings["snapshot_cache_path"] = \
471 normpath(self.settings["snapshot_cache"] + "/" +
472 self.settings["snapshot"])
473 self.snapcache_lock=\
474 LockDir(self.settings["snapshot_cache_path"])
475 print "Caching snapshot to "+self.settings["snapshot_cache_path"]
477 def set_chroot_path(self):
479 NOTE: the trailing slash has been removed
480 Things *could* break if you don't use a proper join()
482 self.settings["chroot_path"]=normpath(self.settings["storedir"]+\
483 "/tmp/"+self.settings["target_subpath"])
484 self.chroot_lock=LockDir(self.settings["chroot_path"])
486 def set_autoresume_path(self):
487 self.settings["autoresume_path"]=normpath(self.settings["storedir"]+\
488 "/tmp/"+self.settings["rel_type"]+"/"+".autoresume-"+\
489 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
490 self.settings["version_stamp"]+"/")
491 if "AUTORESUME" in self.settings:
492 print "The autoresume path is " + self.settings["autoresume_path"]
493 if not os.path.exists(self.settings["autoresume_path"]):
494 os.makedirs(self.settings["autoresume_path"],0755)
496 def set_controller_file(self):
497 self.settings["controller_file"]=normpath(self.settings["sharedir"]+\
498 "/targets/"+self.settings["target"]+"/"+self.settings["target"]+\
501 def set_iso_volume_id(self):
502 if self.settings["spec_prefix"]+"/volid" in self.settings:
503 self.settings["iso_volume_id"]=\
504 self.settings[self.settings["spec_prefix"]+"/volid"]
505 if len(self.settings["iso_volume_id"])>32:
506 raise CatalystError,\
507 "ISO volume ID must not exceed 32 characters."
509 self.settings["iso_volume_id"]="catalyst "+self.settings["snapshot"]
511 def set_action_sequence(self):
512 """ Default action sequence for run method """
513 self.settings["action_sequence"]=["unpack","unpack_snapshot",\
514 "setup_confdir","portage_overlay",\
515 "base_dirs","bind","chroot_setup","setup_environment",\
516 "run_local","preclean","unbind","clean"]
517 # if "TARBALL" in self.settings or \
518 # "FETCH" not in self.settings:
519 if "FETCH" not in self.settings:
520 self.settings["action_sequence"].append("capture")
521 self.settings["action_sequence"].append("clear_autoresume")
524 if self.settings["spec_prefix"]+"/use" in self.settings:
525 self.settings["use"]=\
526 self.settings[self.settings["spec_prefix"]+"/use"]
527 del self.settings[self.settings["spec_prefix"]+"/use"]
528 if "use" not in self.settings:
529 self.settings["use"]=""
530 if type(self.settings["use"])==types.StringType:
531 self.settings["use"]=self.settings["use"].split()
533 # Force bindist when options ask for it
534 if "BINDIST" in self.settings:
535 self.settings["use"].append("bindist")
537 def set_stage_path(self):
538 self.settings["stage_path"]=normpath(self.settings["chroot_path"])
540 def set_mounts(self):
543 def set_packages(self):
547 if self.settings["spec_prefix"]+"/rm" in self.settings:
548 if type(self.settings[self.settings["spec_prefix"]+\
549 "/rm"])==types.StringType:
550 self.settings[self.settings["spec_prefix"]+"/rm"]=\
551 self.settings[self.settings["spec_prefix"]+"/rm"].split()
553 def set_linuxrc(self):
554 if self.settings["spec_prefix"]+"/linuxrc" in self.settings:
555 if type(self.settings[self.settings["spec_prefix"]+\
556 "/linuxrc"])==types.StringType:
557 self.settings["linuxrc"]=\
558 self.settings[self.settings["spec_prefix"]+"/linuxrc"]
559 del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
561 def set_busybox_config(self):
562 if self.settings["spec_prefix"]+"/busybox_config" in self.settings:
563 if type(self.settings[self.settings["spec_prefix"]+\
564 "/busybox_config"])==types.StringType:
565 self.settings["busybox_config"]=\
566 self.settings[self.settings["spec_prefix"]+"/busybox_config"]
567 del self.settings[self.settings["spec_prefix"]+"/busybox_config"]
569 def set_portage_overlay(self):
570 if "portage_overlay" in self.settings:
571 if type(self.settings["portage_overlay"])==types.StringType:
572 self.settings["portage_overlay"]=\
573 self.settings["portage_overlay"].split()
574 print "portage_overlay directories are set to: \""+\
575 string.join(self.settings["portage_overlay"])+"\""
577 def set_overlay(self):
578 if self.settings["spec_prefix"]+"/overlay" in self.settings:
579 if type(self.settings[self.settings["spec_prefix"]+\
580 "/overlay"])==types.StringType:
581 self.settings[self.settings["spec_prefix"]+"/overlay"]=\
582 self.settings[self.settings["spec_prefix"]+\
585 def set_root_overlay(self):
586 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
587 if type(self.settings[self.settings["spec_prefix"]+\
588 "/root_overlay"])==types.StringType:
589 self.settings[self.settings["spec_prefix"]+"/root_overlay"]=\
590 self.settings[self.settings["spec_prefix"]+\
591 "/root_overlay"].split()
593 def set_root_path(self):
594 """ ROOT= variable for emerges """
595 self.settings["root_path"]="/"
597 def set_valid_build_kernel_vars(self,addlargs):
598 if "boot/kernel" in addlargs:
599 if type(addlargs["boot/kernel"])==types.StringType:
600 loopy=[addlargs["boot/kernel"]]
602 loopy=addlargs["boot/kernel"]
605 self.valid_values.append("boot/kernel/"+x+"/aliases")
606 self.valid_values.append("boot/kernel/"+x+"/config")
607 self.valid_values.append("boot/kernel/"+x+"/console")
608 self.valid_values.append("boot/kernel/"+x+"/extraversion")
609 self.valid_values.append("boot/kernel/"+x+"/gk_action")
610 self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
611 self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
612 self.valid_values.append("boot/kernel/"+x+"/machine_type")
613 self.valid_values.append("boot/kernel/"+x+"/sources")
614 self.valid_values.append("boot/kernel/"+x+"/softlevel")
615 self.valid_values.append("boot/kernel/"+x+"/use")
616 self.valid_values.append("boot/kernel/"+x+"/packages")
617 if "boot/kernel/"+x+"/packages" in addlargs:
618 if type(addlargs["boot/kernel/"+x+\
619 "/packages"])==types.StringType:
620 addlargs["boot/kernel/"+x+"/packages"]=\
621 [addlargs["boot/kernel/"+x+"/packages"]]
623 def set_build_kernel_vars(self):
624 if self.settings["spec_prefix"]+"/gk_mainargs" in self.settings:
625 self.settings["gk_mainargs"]=\
626 self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
627 del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
629 def kill_chroot_pids(self):
630 print "Checking for processes running in chroot and killing them."
633 Force environment variables to be exported so script can see them
635 self.setup_environment()
637 if os.path.exists(self.settings["sharedir"]+\
638 "/targets/support/kill-chroot-pids.sh"):
639 cmd("/bin/bash "+self.settings["sharedir"]+\
640 "/targets/support/kill-chroot-pids.sh",\
641 "kill-chroot-pids script failed.",env=self.env)
643 def mount_safety_check(self):
645 Check and verify that none of our paths in mypath are mounted. We don't
646 want to clean up with things still mounted, and this allows us to check.
647 Returns 1 on ok, 0 on "something is still mounted" case.
650 if not os.path.exists(self.settings["chroot_path"]):
653 print "self.mounts =", self.mounts
654 for x in self.mounts:
655 target = normpath(self.settings["chroot_path"] + self.target_mounts[x])
656 print "mount_safety_check() x =", x, target
657 if not os.path.exists(target):
661 """ Something is still mounted "" """
663 print target + " is still mounted; performing auto-bind-umount...",
664 """ Try to umount stuff ourselves """
667 raise CatalystError, "Auto-unbind failed for " + target
669 print "Auto-unbind successful..."
670 except CatalystError:
671 raise CatalystError, "Unable to auto-unbind " + target
676 clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+\
679 if "SEEDCACHE" in self.settings:
680 if os.path.isdir(self.settings["source_path"]):
681 """ SEEDCACHE Is a directory, use rsync """
682 unpack_cmd="rsync -a --delete "+self.settings["source_path"]+\
683 " "+self.settings["chroot_path"]
684 display_msg="\nStarting rsync from "+\
685 self.settings["source_path"]+"\nto "+\
686 self.settings["chroot_path"]+\
687 " (This may take some time) ...\n"
688 error_msg="Rsync of "+self.settings["source_path"]+" to "+\
689 self.settings["chroot_path"]+" failed."
691 """ SEEDCACHE is a not a directory, try untar'ing """
692 print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
693 display_msg="\nStarting tar extract from "+\
694 self.settings["source_path"]+"\nto "+\
695 self.settings["chroot_path"]+\
696 " (This may take some time) ...\n"
697 if "bz2" == self.settings["chroot_path"][-3:]:
698 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
699 self.settings["chroot_path"]
701 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
702 self.settings["chroot_path"]
703 error_msg="Tarball extraction of "+\
704 self.settings["source_path"]+" to "+\
705 self.settings["chroot_path"]+" failed."
707 """ No SEEDCACHE, use tar """
708 display_msg="\nStarting tar extract from "+\
709 self.settings["source_path"]+"\nto "+\
710 self.settings["chroot_path"]+\
711 " (This may take some time) ...\n"
712 if "bz2" == self.settings["chroot_path"][-3:]:
713 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
714 self.settings["chroot_path"]
716 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
717 self.settings["chroot_path"]
718 error_msg="Tarball extraction of "+self.settings["source_path"]+\
719 " to "+self.settings["chroot_path"]+" failed."
721 if "AUTORESUME" in self.settings:
722 if os.path.isdir(self.settings["source_path"]) \
723 and os.path.exists(self.settings["autoresume_path"]+"unpack"):
724 """ Autoresume is valid, SEEDCACHE is valid """
726 invalid_snapshot=False
728 elif os.path.isfile(self.settings["source_path"]) \
729 and self.settings["source_path_hash"]==clst_unpack_hash:
730 """ Autoresume is valid, tarball is valid """
732 invalid_snapshot=True
734 elif os.path.isdir(self.settings["source_path"]) \
735 and not os.path.exists(self.settings["autoresume_path"]+\
737 """ Autoresume is invalid, SEEDCACHE """
739 invalid_snapshot=False
741 elif os.path.isfile(self.settings["source_path"]) \
742 and self.settings["source_path_hash"]!=clst_unpack_hash:
743 """ Autoresume is invalid, tarball """
745 invalid_snapshot=True
747 """ No autoresume, SEEDCACHE """
748 if "SEEDCACHE" in self.settings:
749 """ SEEDCACHE so let's run rsync and let it clean up """
750 if os.path.isdir(self.settings["source_path"]):
752 invalid_snapshot=False
753 elif os.path.isfile(self.settings["source_path"]):
754 """ Tarball so unpack and remove anything already there """
756 invalid_snapshot=True
757 """ No autoresume, no SEEDCACHE """
759 """ Tarball so unpack and remove anything already there """
760 if os.path.isfile(self.settings["source_path"]):
762 invalid_snapshot=True
763 elif os.path.isdir(self.settings["source_path"]):
764 """ We should never reach this, so something is very wrong """
765 raise CatalystError,\
766 "source path is a dir but seedcache is not enabled"
769 self.mount_safety_check()
772 if "AUTORESUME" in self.settings:
773 print "No Valid Resume point detected, cleaning up..."
775 self.clear_autoresume()
778 if not os.path.exists(self.settings["chroot_path"]):
779 os.makedirs(self.settings["chroot_path"])
781 if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
782 os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
784 if "PKGCACHE" in self.settings:
785 if not os.path.exists(self.settings["pkgcache_path"]):
786 os.makedirs(self.settings["pkgcache_path"],0755)
788 if "KERNCACHE" in self.settings:
789 if not os.path.exists(self.settings["kerncache_path"]):
790 os.makedirs(self.settings["kerncache_path"],0755)
793 cmd(unpack_cmd,error_msg,env=self.env)
795 if "source_path_hash" in self.settings:
796 myf=open(self.settings["autoresume_path"]+"unpack","w")
797 myf.write(self.settings["source_path_hash"])
800 touch(self.settings["autoresume_path"]+"unpack")
802 print "Resume point detected, skipping unpack operation..."
804 def unpack_snapshot(self):
806 snapshot_hash=read_from_clst(self.settings["autoresume_path"]+\
809 if "SNAPCACHE" in self.settings:
810 snapshot_cache_hash=\
811 read_from_clst(self.settings["snapshot_cache_path"] + "/" +
813 destdir=self.settings["snapshot_cache_path"]
814 if "bz2" == self.settings["chroot_path"][-3:]:
815 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+destdir
817 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+destdir
818 unpack_errmsg="Error unpacking snapshot"
819 cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+\
820 self.settings["snapshot_cache_path"]+\
821 " (This can take a long time)..."
822 cleanup_errmsg="Error removing existing snapshot cache directory."
823 self.snapshot_lock_object=self.snapcache_lock
825 if self.settings["snapshot_path_hash"]==snapshot_cache_hash:
826 print "Valid snapshot cache, skipping unpack of portage tree..."
829 destdir = normpath(self.settings["chroot_path"] + self.settings["portdir"])
830 cleanup_errmsg="Error removing existing snapshot directory."
832 "Cleaning up existing portage tree (This can take a long time)..."
833 if "bz2" == self.settings["chroot_path"][-3:]:
834 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+\
835 self.settings["chroot_path"]+"/usr"
837 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+\
838 self.settings["chroot_path"]+"/usr"
839 unpack_errmsg="Error unpacking snapshot"
841 if "AUTORESUME" in self.settings \
842 and os.path.exists(self.settings["chroot_path"]+\
843 self.settings["portdir"]) \
844 and os.path.exists(self.settings["autoresume_path"]\
846 and self.settings["snapshot_path_hash"] == snapshot_hash:
848 "Valid Resume point detected, skipping unpack of portage tree..."
852 if "SNAPCACHE" in self.settings:
853 self.snapshot_lock_object.write_lock()
854 if os.path.exists(destdir):
856 cleanup_cmd="rm -rf "+destdir
857 cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
858 if not os.path.exists(destdir):
859 os.makedirs(destdir,0755)
861 print "Unpacking portage tree (This can take a long time) ..."
862 cmd(unpack_cmd,unpack_errmsg,env=self.env)
864 if "SNAPCACHE" in self.settings:
865 myf=open(self.settings["snapshot_cache_path"] +
866 "/" + "catalyst-hash","w")
867 myf.write(self.settings["snapshot_path_hash"])
870 print "Setting snapshot autoresume point"
871 myf=open(self.settings["autoresume_path"]+"unpack_portage","w")
872 myf.write(self.settings["snapshot_path_hash"])
875 if "SNAPCACHE" in self.settings:
876 self.snapshot_lock_object.unlock()
878 def config_profile_link(self):
879 if "AUTORESUME" in self.settings \
880 and os.path.exists(self.settings["autoresume_path"]+\
881 "config_profile_link"):
883 "Resume point detected, skipping config_profile_link operation..."
885 # TODO: zmedico and I discussed making this a directory and pushing
886 # in a parent file, as well as other user-specified configuration.
887 print "Configuring profile link..."
888 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.profile",\
889 "Error zapping profile link",env=self.env)
890 cmd("mkdir -p "+self.settings["chroot_path"]+"/etc/portage/")
891 cmd("ln -sf ../.." + self.settings["portdir"] + "/profiles/" + \
892 self.settings["target_profile"]+" "+\
893 self.settings["chroot_path"]+"/etc/portage/make.profile",\
894 "Error creating profile link",env=self.env)
895 touch(self.settings["autoresume_path"]+"config_profile_link")
897 def setup_confdir(self):
898 if "AUTORESUME" in self.settings \
899 and os.path.exists(self.settings["autoresume_path"]+\
901 print "Resume point detected, skipping setup_confdir operation..."
903 if "portage_confdir" in self.settings:
904 print "Configuring /etc/portage..."
905 cmd("rsync -a "+self.settings["portage_confdir"]+"/ "+\
906 self.settings["chroot_path"]+"/etc/portage/",\
907 "Error copying /etc/portage",env=self.env)
908 touch(self.settings["autoresume_path"]+"setup_confdir")
910 def portage_overlay(self):
911 """ We copy the contents of our overlays to /usr/local/portage """
912 if "portage_overlay" in self.settings:
913 for x in self.settings["portage_overlay"]:
914 if os.path.exists(x):
915 print "Copying overlay dir " +x
916 cmd("mkdir -p "+self.settings["chroot_path"]+\
917 self.settings["local_overlay"],\
918 "Could not make portage_overlay dir",env=self.env)
919 cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+\
920 self.settings["local_overlay"],\
921 "Could not copy portage_overlay",env=self.env)
923 def root_overlay(self):
924 """ Copy over the root_overlay """
925 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
926 for x in self.settings[self.settings["spec_prefix"]+\
928 if os.path.exists(x):
929 print "Copying root_overlay: "+x
930 cmd("rsync -a "+x+"/ "+\
931 self.settings["chroot_path"],\
932 self.settings["spec_prefix"]+"/root_overlay: "+x+\
933 " copy failed.",env=self.env)
939 for x in self.mounts:
940 #print "bind(); x =", x
941 target = normpath(self.settings["chroot_path"] + self.target_mounts[x])
942 if not os.path.exists(target):
943 os.makedirs(target, 0755)
945 if not os.path.exists(self.mountmap[x]):
946 if self.mountmap[x] not in ["tmpfs", "shmfs"]:
947 os.makedirs(self.mountmap[x], 0755)
950 #print "bind(); src =", src
951 if "SNAPCACHE" in self.settings and x == "portdir":
952 self.snapshot_lock_object.read_lock()
953 if os.uname()[0] == "FreeBSD":
955 cmd = "mount -t devfs none " + target
956 retval=os.system(cmd)
958 cmd = "mount_nullfs " + src + " " + target
959 retval=os.system(cmd)
962 if "var_tmpfs_portage" in self.settings:
963 cmd = "mount -t tmpfs -o size=" + \
964 self.settings["var_tmpfs_portage"] + "G " + \
966 retval=os.system(cmd)
968 cmd = "mount -t tmpfs -o noexec,nosuid,nodev shm " + target
969 retval=os.system(cmd)
971 cmd = "mount --bind " + src + " " + target
972 #print "bind(); cmd =", cmd
973 retval=os.system(cmd)
976 raise CatalystError,"Couldn't bind mount " + src
980 mypath=self.settings["chroot_path"]
981 myrevmounts=self.mounts[:]
982 myrevmounts.reverse()
983 """ Unmount in reverse order for nested bind-mounts """
984 for x in myrevmounts:
985 target = normpath(mypath + self.target_mounts[x])
986 if not os.path.exists(target):
989 if not ismount(target):
992 retval=os.system("umount " + target)
995 warn("First attempt to unmount: " + target + " failed.")
996 warn("Killing any pids still running in the chroot")
998 self.kill_chroot_pids()
1000 retval2 = os.system("umount " + target)
1003 warn("Couldn't umount bind mount: " + target)
1005 if "SNAPCACHE" in self.settings and x == "/usr/portage":
1008 It's possible the snapshot lock object isn't created yet.
1009 This is because mount safety check calls unbind before the
1010 target is fully initialized
1012 self.snapshot_lock_object.unlock()
1017 if any bind mounts really failed, then we need to raise
1018 this to potentially prevent an upcoming bash stage cleanup script
1019 from wiping our bind mounts.
1021 raise CatalystError,\
1022 "Couldn't umount one or more bind-mounts; aborting for safety."
1024 def chroot_setup(self):
1025 self.makeconf=read_makeconf(self.settings["chroot_path"]+\
1026 "/etc/portage/make.conf")
1027 self.override_cbuild()
1028 self.override_chost()
1029 self.override_cflags()
1030 self.override_cxxflags()
1031 self.override_ldflags()
1032 if "AUTORESUME" in self.settings \
1033 and os.path.exists(self.settings["autoresume_path"]+"chroot_setup"):
1034 print "Resume point detected, skipping chroot_setup operation..."
1036 print "Setting up chroot..."
1038 #self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/portage/make.conf")
1040 cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
1041 "Could not copy resolv.conf into place.",env=self.env)
1043 """ Copy over the envscript, if applicable """
1044 if "ENVSCRIPT" in self.settings:
1045 if not os.path.exists(self.settings["ENVSCRIPT"]):
1046 raise CatalystError,\
1047 "Can't find envscript "+self.settings["ENVSCRIPT"]
1049 print "\nWarning!!!!"
1050 print "\tOverriding certain env variables may cause catastrophic failure."
1051 print "\tIf your build fails look here first as the possible problem."
1052 print "\tCatalyst assumes you know what you are doing when setting"
1053 print "\t\tthese variables."
1054 print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
1055 print "\tYou have been warned\n"
1057 cmd("cp "+self.settings["ENVSCRIPT"]+" "+\
1058 self.settings["chroot_path"]+"/tmp/envscript",\
1059 "Could not copy envscript into place.",env=self.env)
1062 Copy over /etc/hosts from the host in case there are any
1063 specialties in there
1065 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
1066 cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+\
1067 self.settings["chroot_path"]+"/etc/hosts.catalyst",\
1068 "Could not backup /etc/hosts",env=self.env)
1069 cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts",\
1070 "Could not copy /etc/hosts",env=self.env)
1072 """ Modify and write out make.conf (for the chroot) """
1073 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.conf",\
1074 "Could not remove "+self.settings["chroot_path"]+\
1075 "/etc/portage/make.conf",env=self.env)
1076 myf=open(self.settings["chroot_path"]+"/etc/portage/make.conf","w")
1077 myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
1078 myf.write("# Please consult /usr/share/portage/config/make.conf.example for a more\n# detailed example.\n")
1079 if "CFLAGS" in self.settings:
1080 myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
1081 if "CXXFLAGS" in self.settings:
1082 if self.settings["CXXFLAGS"]!=self.settings["CFLAGS"]:
1083 myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
1085 myf.write('CXXFLAGS="${CFLAGS}"\n')
1087 myf.write('CXXFLAGS="${CFLAGS}"\n')
1089 if "LDFLAGS" in self.settings:
1090 myf.write("# LDFLAGS is unsupported. USE AT YOUR OWN RISK!\n")
1091 myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
1092 if "CBUILD" in self.settings:
1093 myf.write("# This should not be changed unless you know exactly what you are doing. You\n# should probably be using a different stage, instead.\n")
1094 myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
1096 myf.write("# WARNING: Changing your CHOST is not something that should be done lightly.\n# Please consult http://www.gentoo.org/doc/en/change-chost.xml before changing.\n")
1097 myf.write('CHOST="'+self.settings["CHOST"]+'"\n')
1099 """ Figure out what our USE vars are for building """
1101 if "HOSTUSE" in self.settings:
1102 myusevars.extend(self.settings["HOSTUSE"])
1104 if "use" in self.settings:
1105 myusevars.extend(self.settings["use"])
1108 myf.write("# These are the USE flags that were used in addition to what is provided by the\n# profile used for building.\n")
1109 myusevars = sorted(set(myusevars))
1110 myf.write('USE="'+string.join(myusevars)+'"\n')
1111 if '-*' in myusevars:
1112 print "\nWarning!!! "
1113 print "\tThe use of -* in "+self.settings["spec_prefix"]+\
1114 "/use will cause portage to ignore"
1115 print "\tpackage.use in the profile and portage_confdir. You've been warned!"
1117 myf.write('PORTDIR="%s"\n' % self.settings['portdir'])
1118 myf.write('DISTDIR="%s"\n' % self.settings['distdir'])
1119 myf.write('PKGDIR="%s"\n' % self.settings['packagedir'])
1121 """ Setup the portage overlay """
1122 if "portage_overlay" in self.settings:
1123 myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
1126 cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
1127 self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
1128 "Could not backup /etc/portage/make.conf",env=self.env)
1129 touch(self.settings["autoresume_path"]+"chroot_setup")
1132 if "AUTORESUME" in self.settings \
1133 and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
1134 print "Resume point detected, skipping fsscript operation..."
1136 if "fsscript" in self.settings:
1137 if os.path.exists(self.settings["controller_file"]):
1138 cmd("/bin/bash "+self.settings["controller_file"]+\
1139 " fsscript","fsscript script failed.",env=self.env)
1140 touch(self.settings["autoresume_path"]+"fsscript")
1143 if "AUTORESUME" in self.settings \
1144 and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
1145 print "Resume point detected, skipping rcupdate operation..."
1147 if os.path.exists(self.settings["controller_file"]):
1148 cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
1149 "rc-update script failed.",env=self.env)
1150 touch(self.settings["autoresume_path"]+"rcupdate")
1153 if "AUTORESUME" in self.settings \
1154 and os.path.exists(self.settings["autoresume_path"]+"clean"):
1155 print "Resume point detected, skipping clean operation..."
1157 for x in self.settings["cleanables"]:
1158 print "Cleaning chroot: "+x+"... "
1159 cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
1162 """ Put /etc/hosts back into place """
1163 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
1164 cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
1165 self.settings["chroot_path"]+"/etc/hosts",\
1166 "Could not replace /etc/hosts",env=self.env)
1168 """ Remove our overlay """
1169 if os.path.exists(self.settings["chroot_path"] + self.settings["local_overlay"]):
1170 cmd("rm -rf " + self.settings["chroot_path"] + self.settings["local_overlay"],
1171 "Could not remove " + self.settings["local_overlay"], env=self.env)
1172 cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
1173 "/etc/portage/make.conf",\
1174 "Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
1176 """ Clean up old and obsoleted files in /etc """
1177 if os.path.exists(self.settings["stage_path"]+"/etc"):
1178 cmd("find "+self.settings["stage_path"]+\
1179 "/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
1180 "Could not remove stray files in /etc",env=self.env)
1182 if os.path.exists(self.settings["controller_file"]):
1183 cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
1184 "clean script failed.",env=self.env)
1185 touch(self.settings["autoresume_path"]+"clean")
1188 if "AUTORESUME" in self.settings \
1189 and os.path.exists(self.settings["autoresume_path"]+"empty"):
1190 print "Resume point detected, skipping empty operation..."
1192 if self.settings["spec_prefix"]+"/empty" in self.settings:
1193 if type(self.settings[self.settings["spec_prefix"]+\
1194 "/empty"])==types.StringType:
1195 self.settings[self.settings["spec_prefix"]+"/empty"]=\
1196 self.settings[self.settings["spec_prefix"]+\
1198 for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
1199 myemp=self.settings["destpath"]+x
1200 if not os.path.isdir(myemp) or os.path.islink(myemp):
1201 print x,"not a directory or does not exist, skipping 'empty' operation."
1203 print "Emptying directory",x
1205 stat the dir, delete the dir, recreate the dir and set
1206 the proper perms and ownership
1208 mystat=os.stat(myemp)
1209 shutil.rmtree(myemp)
1210 os.makedirs(myemp,0755)
1211 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1212 os.chmod(myemp,mystat[ST_MODE])
1213 touch(self.settings["autoresume_path"]+"empty")
1216 if "AUTORESUME" in self.settings \
1217 and os.path.exists(self.settings["autoresume_path"]+"remove"):
1218 print "Resume point detected, skipping remove operation..."
1220 if self.settings["spec_prefix"]+"/rm" in self.settings:
1221 for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
1223 We're going to shell out for all these cleaning
1224 operations, so we get easy glob handling.
1226 print "livecd: removing "+x
1227 os.system("rm -rf "+self.settings["chroot_path"]+x)
1229 if os.path.exists(self.settings["controller_file"]):
1230 cmd("/bin/bash "+self.settings["controller_file"]+\
1231 " clean","Clean failed.",env=self.env)
1232 touch(self.settings["autoresume_path"]+"remove")
1238 if "AUTORESUME" in self.settings \
1239 and os.path.exists(self.settings["autoresume_path"]+"preclean"):
1240 print "Resume point detected, skipping preclean operation..."
1243 if os.path.exists(self.settings["controller_file"]):
1244 cmd("/bin/bash "+self.settings["controller_file"]+\
1245 " preclean","preclean script failed.",env=self.env)
1246 touch(self.settings["autoresume_path"]+"preclean")
1250 raise CatalystError, "Build failed, could not execute preclean"
1253 if "AUTORESUME" in self.settings \
1254 and os.path.exists(self.settings["autoresume_path"]+"capture"):
1255 print "Resume point detected, skipping capture operation..."
1257 """ Capture target in a tarball """
1258 mypath=self.settings["target_path"].split("/")
1259 """ Remove filename from path """
1260 mypath=string.join(mypath[:-1],"/")
1262 """ Now make sure path exists """
1263 if not os.path.exists(mypath):
1266 print "Creating stage tarball..."
1268 cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
1269 self.settings["stage_path"]+" .",\
1270 "Couldn't create stage tarball",env=self.env)
1272 self.gen_contents_file(self.settings["target_path"])
1273 self.gen_digest_file(self.settings["target_path"])
1275 touch(self.settings["autoresume_path"]+"capture")
1277 def run_local(self):
1278 if "AUTORESUME" in self.settings \
1279 and os.path.exists(self.settings["autoresume_path"]+"run_local"):
1280 print "Resume point detected, skipping run_local operation..."
1283 if os.path.exists(self.settings["controller_file"]):
1284 cmd("/bin/bash "+self.settings["controller_file"]+" run",\
1285 "run script failed.",env=self.env)
1286 touch(self.settings["autoresume_path"]+"run_local")
1288 except CatalystError:
1290 raise CatalystError,"Stage build aborting due to error."
1292 def setup_environment(self):
1294 Modify the current environment. This is an ugly hack that should be
1295 fixed. We need this to use the os.system() call since we can't
1296 specify our own environ
1298 for x in self.settings.keys():
1299 """ Sanitize var names by doing "s|/-.|_|g" """
1300 varname="clst_"+string.replace(x,"/","_")
1301 varname=string.replace(varname,"-","_")
1302 varname=string.replace(varname,".","_")
1303 if type(self.settings[x])==types.StringType:
1304 """ Prefix to prevent namespace clashes """
1305 #os.environ[varname]=self.settings[x]
1306 self.env[varname]=self.settings[x]
1307 elif type(self.settings[x])==types.ListType:
1308 #os.environ[varname]=string.join(self.settings[x])
1309 self.env[varname]=string.join(self.settings[x])
1310 elif type(self.settings[x])==types.BooleanType:
1311 if self.settings[x]:
1312 self.env[varname]="true"
1314 self.env[varname]="false"
1315 if "makeopts" in self.settings:
1316 self.env["MAKEOPTS"]=self.settings["makeopts"]
1319 self.chroot_lock.write_lock()
1321 """ Kill any pids in the chroot "" """
1322 self.kill_chroot_pids()
1324 """ Check for mounts right away and abort if we cannot unmount them """
1325 self.mount_safety_check()
1327 if "CLEAR_AUTORESUME" in self.settings:
1328 self.clear_autoresume()
1330 if "PURGETMPONLY" in self.settings:
1334 if "PURGEONLY" in self.settings:
1338 if "PURGE" in self.settings:
1341 for x in self.settings["action_sequence"]:
1342 print "--- Running action sequence: "+x
1345 apply(getattr(self,x))
1347 self.mount_safety_check()
1350 self.chroot_lock.unlock()
1353 if "AUTORESUME" in self.settings \
1354 and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
1355 print "Resume point detected, skipping unmerge operation..."
1357 if self.settings["spec_prefix"]+"/unmerge" in self.settings:
1358 if type(self.settings[self.settings["spec_prefix"]+\
1359 "/unmerge"])==types.StringType:
1360 self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
1361 [self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1363 self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1365 for x in range(0,len(myunmerge)):
1367 Surround args with quotes for passing to bash, allows
1368 things like "<" to remain intact
1370 myunmerge[x]="'"+myunmerge[x]+"'"
1371 myunmerge=string.join(myunmerge)
1373 """ Before cleaning, unmerge stuff """
1375 cmd("/bin/bash "+self.settings["controller_file"]+\
1376 " unmerge "+ myunmerge,"Unmerge script failed.",\
1378 print "unmerge shell script"
1379 except CatalystError:
1382 touch(self.settings["autoresume_path"]+"unmerge")
1384 def target_setup(self):
1385 if "AUTORESUME" in self.settings \
1386 and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
1387 print "Resume point detected, skipping target_setup operation..."
1389 print "Setting up filesystems per filesystem type"
1390 cmd("/bin/bash "+self.settings["controller_file"]+\
1391 " target_image_setup "+ self.settings["target_path"],\
1392 "target_image_setup script failed.",env=self.env)
1393 touch(self.settings["autoresume_path"]+"target_setup")
1395 def setup_overlay(self):
1396 if "AUTORESUME" in self.settings \
1397 and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
1398 print "Resume point detected, skipping setup_overlay operation..."
1400 if self.settings["spec_prefix"]+"/overlay" in self.settings:
1401 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
1402 if os.path.exists(x):
1403 cmd("rsync -a "+x+"/ "+\
1404 self.settings["target_path"],\
1405 self.settings["spec_prefix"]+"overlay: "+x+\
1406 " copy failed.",env=self.env)
1407 touch(self.settings["autoresume_path"]+"setup_overlay")
1409 def create_iso(self):
1410 if "AUTORESUME" in self.settings \
1411 and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
1412 print "Resume point detected, skipping create_iso operation..."
1414 """ Create the ISO """
1415 if "iso" in self.settings:
1416 cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1417 self.settings["iso"],"ISO creation script failed.",\
1419 self.gen_contents_file(self.settings["iso"])
1420 self.gen_digest_file(self.settings["iso"])
1421 touch(self.settings["autoresume_path"]+"create_iso")
1423 print "WARNING: livecd/iso was not defined."
1424 print "An ISO Image will not be created."
1426 def build_packages(self):
1427 if "AUTORESUME" in self.settings \
1428 and os.path.exists(self.settings["autoresume_path"]+\
1430 print "Resume point detected, skipping build_packages operation..."
1432 if self.settings["spec_prefix"]+"/packages" in self.settings:
1433 if "AUTORESUME" in self.settings \
1434 and os.path.exists(self.settings["autoresume_path"]+\
1436 print "Resume point detected, skipping build_packages operation..."
1439 list_bashify(self.settings[self.settings["spec_prefix"]\
1442 cmd("/bin/bash "+self.settings["controller_file"]+\
1443 " build_packages "+mypack,\
1444 "Error in attempt to build packages",env=self.env)
1445 touch(self.settings["autoresume_path"]+"build_packages")
1446 except CatalystError:
1448 raise CatalystError,self.settings["spec_prefix"]+\
1449 "build aborting due to error."
1451 def build_kernel(self):
1452 "Build all configured kernels"
1453 if "AUTORESUME" in self.settings \
1454 and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
1455 print "Resume point detected, skipping build_kernel operation..."
1457 if "boot/kernel" in self.settings:
1459 mynames=self.settings["boot/kernel"]
1460 if type(mynames)==types.StringType:
1463 Execute the script that sets up the kernel build environment
1465 cmd("/bin/bash "+self.settings["controller_file"]+\
1466 " pre-kmerge ","Runscript pre-kmerge failed",\
1468 for kname in mynames:
1469 self._build_kernel(kname=kname)
1470 touch(self.settings["autoresume_path"]+"build_kernel")
1471 except CatalystError:
1473 raise CatalystError,\
1474 "build aborting due to kernel build error."
1476 def _build_kernel(self, kname):
1477 "Build a single configured kernel by name"
1478 if "AUTORESUME" in self.settings \
1479 and os.path.exists(self.settings["autoresume_path"]\
1480 +"build_kernel_"+kname):
1481 print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1483 self._copy_kernel_config(kname=kname)
1486 If we need to pass special options to the bootloader
1487 for this kernel put them into the environment
1489 if "boot/kernel/"+kname+"/kernelopts" in self.settings:
1490 myopts=self.settings["boot/kernel/"+kname+\
1493 if type(myopts) != types.StringType:
1494 myopts = string.join(myopts)
1495 self.env[kname+"_kernelopts"]=myopts
1498 self.env[kname+"_kernelopts"]=""
1500 if "boot/kernel/"+kname+"/extraversion" not in self.settings:
1501 self.settings["boot/kernel/"+kname+\
1504 self.env["clst_kextraversion"]=\
1505 self.settings["boot/kernel/"+kname+\
1508 self._copy_initramfs_overlay(kname=kname)
1510 """ Execute the script that builds the kernel """
1511 cmd("/bin/bash "+self.settings["controller_file"]+\
1513 "Runscript kernel build failed",env=self.env)
1515 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1516 if os.path.exists(self.settings["chroot_path"]+\
1517 "/tmp/initramfs_overlay/"):
1518 print "Cleaning up temporary overlay dir"
1519 cmd("rm -R "+self.settings["chroot_path"]+\
1520 "/tmp/initramfs_overlay/",env=self.env)
1522 touch(self.settings["autoresume_path"]+\
1523 "build_kernel_"+kname)
1526 Execute the script that cleans up the kernel build
1529 cmd("/bin/bash "+self.settings["controller_file"]+\
1531 "Runscript post-kmerge failed",env=self.env)
1533 def _copy_kernel_config(self, kname):
1534 if "boot/kernel/"+kname+"/config" in self.settings:
1535 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1537 raise CatalystError,\
1538 "Can't find kernel config: "+\
1539 self.settings["boot/kernel/"+kname+\
1543 cmd("cp "+self.settings["boot/kernel/"+kname+\
1545 self.settings["chroot_path"]+"/var/tmp/"+\
1547 "Couldn't copy kernel config: "+\
1548 self.settings["boot/kernel/"+kname+\
1549 "/config"],env=self.env)
1551 except CatalystError:
1554 def _copy_initramfs_overlay(self, kname):
1555 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1556 if os.path.exists(self.settings["boot/kernel/"+\
1557 kname+"/initramfs_overlay"]):
1558 print "Copying initramfs_overlay dir "+\
1559 self.settings["boot/kernel/"+kname+\
1560 "/initramfs_overlay"]
1563 self.settings["chroot_path"]+\
1564 "/tmp/initramfs_overlay/"+\
1565 self.settings["boot/kernel/"+kname+\
1566 "/initramfs_overlay"],env=self.env)
1568 cmd("cp -R "+self.settings["boot/kernel/"+\
1569 kname+"/initramfs_overlay"]+"/* "+\
1570 self.settings["chroot_path"]+\
1571 "/tmp/initramfs_overlay/"+\
1572 self.settings["boot/kernel/"+kname+\
1573 "/initramfs_overlay"],env=self.env)
1575 def bootloader(self):
1576 if "AUTORESUME" in self.settings \
1577 and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
1578 print "Resume point detected, skipping bootloader operation..."
1581 cmd("/bin/bash "+self.settings["controller_file"]+\
1582 " bootloader " + self.settings["target_path"],\
1583 "Bootloader script failed.",env=self.env)
1584 touch(self.settings["autoresume_path"]+"bootloader")
1585 except CatalystError:
1587 raise CatalystError,"Script aborting due to error."
1589 def livecd_update(self):
1590 if "AUTORESUME" in self.settings \
1591 and os.path.exists(self.settings["autoresume_path"]+\
1593 print "Resume point detected, skipping build_packages operation..."
1596 cmd("/bin/bash "+self.settings["controller_file"]+\
1597 " livecd-update","livecd-update failed.",env=self.env)
1598 touch(self.settings["autoresume_path"]+"livecd_update")
1600 except CatalystError:
1602 raise CatalystError,"build aborting due to livecd_update error."
1604 def clear_chroot(self):
1605 myemp=self.settings["chroot_path"]
1606 if os.path.isdir(myemp):
1607 print "Emptying directory",myemp
1609 stat the dir, delete the dir, recreate the dir and set
1610 the proper perms and ownership
1612 mystat=os.stat(myemp)
1613 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1614 """ There's no easy way to change flags recursively in python """
1615 if os.uname()[0] == "FreeBSD":
1616 os.system("chflags -R noschg "+myemp)
1617 shutil.rmtree(myemp)
1618 os.makedirs(myemp,0755)
1619 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1620 os.chmod(myemp,mystat[ST_MODE])
1622 def clear_packages(self):
1623 if "PKGCACHE" in self.settings:
1624 print "purging the pkgcache ..."
1626 myemp=self.settings["pkgcache_path"]
1627 if os.path.isdir(myemp):
1628 print "Emptying directory",myemp
1630 stat the dir, delete the dir, recreate the dir and set
1631 the proper perms and ownership
1633 mystat=os.stat(myemp)
1634 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1635 shutil.rmtree(myemp)
1636 os.makedirs(myemp,0755)
1637 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1638 os.chmod(myemp,mystat[ST_MODE])
1640 def clear_kerncache(self):
1641 if "KERNCACHE" in self.settings:
1642 print "purging the kerncache ..."
1644 myemp=self.settings["kerncache_path"]
1645 if os.path.isdir(myemp):
1646 print "Emptying directory",myemp
1648 stat the dir, delete the dir, recreate the dir and set
1649 the proper perms and ownership
1651 mystat=os.stat(myemp)
1652 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1653 shutil.rmtree(myemp)
1654 os.makedirs(myemp,0755)
1655 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1656 os.chmod(myemp,mystat[ST_MODE])
1658 def clear_autoresume(self):
1659 """ Clean resume points since they are no longer needed """
1660 if "AUTORESUME" in self.settings:
1661 print "Removing AutoResume Points: ..."
1662 myemp=self.settings["autoresume_path"]
1663 if os.path.isdir(myemp):
1664 if "AUTORESUME" in self.settings:
1665 print "Emptying directory",myemp
1667 stat the dir, delete the dir, recreate the dir and set
1668 the proper perms and ownership
1670 mystat=os.stat(myemp)
1671 if os.uname()[0] == "FreeBSD":
1672 cmd("chflags -R noschg "+myemp,\
1673 "Could not remove immutable flag for file "\
1675 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1676 shutil.rmtree(myemp)
1677 os.makedirs(myemp,0755)
1678 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1679 os.chmod(myemp,mystat[ST_MODE])
1681 def gen_contents_file(self,file):
1682 if os.path.exists(file+".CONTENTS"):
1683 os.remove(file+".CONTENTS")
1684 if "contents" in self.settings:
1685 if os.path.exists(file):
1686 myf=open(file+".CONTENTS","w")
1688 for i in self.settings["contents"].split():
1693 contents=generate_contents(file,contents_function=j,\
1694 verbose="VERBOSE" in self.settings)
1699 def gen_digest_file(self,file):
1700 if os.path.exists(file+".DIGESTS"):
1701 os.remove(file+".DIGESTS")
1702 if "digests" in self.settings:
1703 if os.path.exists(file):
1704 myf=open(file+".DIGESTS","w")
1706 for i in self.settings["digests"].split():
1710 for f in [file, file+'.CONTENTS']:
1711 if os.path.exists(f):
1713 for k in hash_map.keys():
1714 hash=generate_hash(f,hash_function=k,verbose=\
1715 "VERBOSE" in self.settings)
1719 hash=generate_hash(f,hash_function=j,verbose=\
1720 "VERBOSE" in self.settings)
1725 countdown(10,"Purging Caches ...")
1726 if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
1727 print "clearing autoresume ..."
1728 self.clear_autoresume()
1730 print "clearing chroot ..."
1733 if "PURGETMPONLY" not in self.settings:
1734 print "clearing package cache ..."
1735 self.clear_packages()
1737 print "clearing kerncache ..."
1738 self.clear_kerncache()
1740 # vim: ts=4 sw=4 sta et sts=4 ai