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",
40 class generic_stage_target(generic_target):
42 This class does all of the chroot setup, copying of files, etc. It is
43 the driver class for pretty much everything that Catalyst does.
45 def __init__(self,myspec,addlargs):
46 self.required_values.extend(["version_stamp","target","subarch",\
47 "rel_type","profile","snapshot","source_subpath"])
49 self.valid_values.extend(["version_stamp","target","subarch",\
50 "rel_type","profile","snapshot","source_subpath","portage_confdir",\
51 "cflags","cxxflags","ldflags","cbuild","hostuse","portage_overlay",\
52 "distcc_hosts","makeopts","pkgcache_path","kerncache_path"])
54 self.set_valid_build_kernel_vars(addlargs)
55 generic_target.__init__(self,myspec,addlargs)
58 The semantics of subarchmap and machinemap changed a bit in 2.0.3 to
59 work better with vapier's CBUILD stuff. I've removed the "monolithic"
60 machinemap from this file and split up its contents amongst the
61 various arch/foo.py files.
63 When register() is called on each module in the arch/ dir, it now
64 returns a tuple instead of acting on the subarchmap dict that is
65 passed to it. The tuple contains the values that were previously
66 added to subarchmap as well as a new list of CHOSTs that go along
67 with that arch. This allows us to build machinemap on the fly based
68 on the keys in subarchmap and the values of the 2nd list returned
71 Also, after talking with vapier. I have a slightly better idea of what
72 certain variables are used for and what they should be set to. Neither
73 'buildarch' or 'hostarch' are used directly, so their value doesn't
74 really matter. They are just compared to determine if we are
75 cross-compiling. Because of this, they are just set to the name of the
76 module in arch/ that the subarch is part of to make things simpler.
77 The entire build process is still based off of 'subarch' like it was
84 arch_dir = self.settings["PythonDir"] + "/arch/"
85 for x in [x[:-3] for x in os.listdir(arch_dir) if x.endswith(".py")]:
89 fh=open(arch_dir + x + ".py")
91 This next line loads the plugin as a module and assigns it to
94 self.archmap[x]=imp.load_module(x,fh,"../arch/" + x + ".py",
95 (".py", "r", imp.PY_SOURCE))
97 This next line registers all the subarches supported in the
100 tmpsubarchmap, tmpmachinemap = self.archmap[x].register()
101 self.subarchmap.update(tmpsubarchmap)
102 for machine in tmpmachinemap:
103 machinemap[machine] = x
104 for subarch in tmpsubarchmap:
105 machinemap[subarch] = x
109 This message should probably change a bit, since everything in
110 the dir should load just fine. If it doesn't, it's probably a
111 syntax error in the module
113 msg("Can't find/load " + x + ".py plugin in " + arch_dir)
115 if "chost" in self.settings:
116 hostmachine = self.settings["chost"].split("-")[0]
117 if hostmachine not in machinemap:
118 raise CatalystError, "Unknown host machine type "+hostmachine
119 self.settings["hostarch"]=machinemap[hostmachine]
121 hostmachine = self.settings["subarch"]
122 if hostmachine in machinemap:
123 hostmachine = machinemap[hostmachine]
124 self.settings["hostarch"]=hostmachine
125 if "cbuild" in self.settings:
126 buildmachine = self.settings["cbuild"].split("-")[0]
128 buildmachine = os.uname()[4]
129 if buildmachine not in machinemap:
130 raise CatalystError, "Unknown build machine type "+buildmachine
131 self.settings["buildarch"]=machinemap[buildmachine]
132 self.settings["crosscompile"]=(self.settings["hostarch"]!=\
133 self.settings["buildarch"])
135 """ Call arch constructor, pass our settings """
137 self.arch=self.subarchmap[self.settings["subarch"]](self.settings)
139 print "Invalid subarch: "+self.settings["subarch"]
140 print "Choose one of the following:",
141 for x in self.subarchmap:
146 print "Using target:",self.settings["target"]
147 """ Print a nice informational message """
148 if self.settings["buildarch"]==self.settings["hostarch"]:
149 print "Building natively for",self.settings["hostarch"]
150 elif self.settings["crosscompile"]:
151 print "Cross-compiling on",self.settings["buildarch"],\
152 "for different machine type",self.settings["hostarch"]
154 print "Building on",self.settings["buildarch"],\
155 "for alternate personality type",self.settings["hostarch"]
157 """ This must be set first as other set_ options depend on this """
158 self.set_spec_prefix()
160 """ Define all of our core variables """
161 self.set_target_profile()
162 self.set_target_subpath()
163 self.set_source_subpath()
166 self.set_snapshot_path()
168 self.set_source_path()
169 self.set_snapcache_path()
170 self.set_chroot_path()
171 self.set_autoresume_path()
173 self.set_stage_path()
174 self.set_target_path()
176 self.set_controller_file()
177 self.set_action_sequence()
179 self.set_cleanables()
180 self.set_iso_volume_id()
181 self.set_build_kernel_vars()
183 self.set_install_mask()
193 self.set_busybox_config()
195 self.set_portage_overlay()
196 self.set_root_overlay()
199 This next line checks to make sure that the specified variables exist
203 file_locate(self.settings,["source_path","snapshot_path","distdir"],\
205 """ If we are using portage_confdir, check that as well. """
206 if "portage_confdir" in self.settings:
207 file_locate(self.settings,["portage_confdir"],expand=0)
209 """ Setup our mount points """
210 # initialize our target mounts.
211 self.target_mounts = TARGET_MOUNTS_DEFAULTS.copy()
213 self.mounts = ["proc", "dev", "portdir", "distdir", "port_tmpdir"]
214 # initialize our source mounts
215 self.mountmap = SOURCE_MOUNTS_DEFAULTS.copy()
216 # update them from settings
217 self.mountmap["distdir"] = self.settings["distdir"]
218 if "SNAPCACHE" not in self.settings:
219 self.mounts.remove("portdir")
220 self.mountmap["portdir"] = None
222 self.mountmap["portdir"] = normpath("/".join([
223 self.settings["snapshot_cache_path"],
224 self.settings["repo_name"],
226 if os.uname()[0] == "Linux":
227 self.mounts.append("devpts")
228 self.mounts.append("shm")
233 Configure any user specified options (either in catalyst.conf or on
236 if "PKGCACHE" in self.settings:
237 self.set_pkgcache_path()
238 print "Location of the package cache is "+\
239 self.settings["pkgcache_path"]
240 self.mounts.append("packagedir")
241 self.mountmap["packagedir"] = self.settings["pkgcache_path"]
243 if "KERNCACHE" in self.settings:
244 self.set_kerncache_path()
245 print "Location of the kerncache is "+\
246 self.settings["kerncache_path"]
247 self.mounts.append("kerncache")
248 self.mountmap["kerncache"] = self.settings["kerncache_path"]
250 if "CCACHE" in self.settings:
251 if "CCACHE_DIR" in os.environ:
252 ccdir=os.environ["CCACHE_DIR"]
253 del os.environ["CCACHE_DIR"]
255 ccdir="/root/.ccache"
256 if not os.path.isdir(ccdir):
257 raise CatalystError,\
258 "Compiler cache support can't be enabled (can't find "+\
260 self.mounts.append("ccache")
261 self.mountmap["ccache"] = ccdir
262 """ for the chroot: """
263 self.env["CCACHE_DIR"] = self.target_mounts["ccache"]
265 if "ICECREAM" in self.settings:
266 self.mounts.append("icecream")
267 self.mountmap["icecream"] = self.settings["icecream"]
268 self.env["PATH"] = self.target_mounts["icecream"] + ":" + \
271 if "port_logdir" in self.settings:
272 self.mounts.append("port_logdir")
273 self.mountmap["port_logdir"] = self.settings["port_logdir"]
274 self.env["PORT_LOGDIR"] = self.settings["port_logdir"]
275 self.env["PORT_LOGDIR_CLEAN"] = PORT_LOGDIR_CLEAN
277 def override_cbuild(self):
278 if "CBUILD" in self.makeconf:
279 self.settings["CBUILD"]=self.makeconf["CBUILD"]
281 def override_chost(self):
282 if "CHOST" in self.makeconf:
283 self.settings["CHOST"]=self.makeconf["CHOST"]
285 def override_cflags(self):
286 if "CFLAGS" in self.makeconf:
287 self.settings["CFLAGS"]=self.makeconf["CFLAGS"]
289 def override_cxxflags(self):
290 if "CXXFLAGS" in self.makeconf:
291 self.settings["CXXFLAGS"]=self.makeconf["CXXFLAGS"]
293 def override_ldflags(self):
294 if "LDFLAGS" in self.makeconf:
295 self.settings["LDFLAGS"]=self.makeconf["LDFLAGS"]
297 def set_install_mask(self):
298 if "install_mask" in self.settings:
299 if type(self.settings["install_mask"])!=types.StringType:
300 self.settings["install_mask"]=\
301 string.join(self.settings["install_mask"])
303 def set_spec_prefix(self):
304 self.settings["spec_prefix"]=self.settings["target"]
306 def set_target_profile(self):
307 self.settings["target_profile"]=self.settings["profile"]
309 def set_target_subpath(self):
310 self.settings["target_subpath"]=self.settings["rel_type"]+"/"+\
311 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
312 self.settings["version_stamp"]
314 def set_source_subpath(self):
315 if type(self.settings["source_subpath"])!=types.StringType:
316 raise CatalystError,\
317 "source_subpath should have been a string. Perhaps you have something wrong in your spec file?"
319 def set_pkgcache_path(self):
320 if "pkgcache_path" in self.settings:
321 if type(self.settings["pkgcache_path"])!=types.StringType:
322 self.settings["pkgcache_path"]=\
323 normpath(string.join(self.settings["pkgcache_path"]))
325 self.settings["pkgcache_path"]=\
326 normpath(self.settings["storedir"]+"/packages/"+\
327 self.settings["target_subpath"]+"/")
329 def set_kerncache_path(self):
330 if "kerncache_path" in self.settings:
331 if type(self.settings["kerncache_path"])!=types.StringType:
332 self.settings["kerncache_path"]=\
333 normpath(string.join(self.settings["kerncache_path"]))
335 self.settings["kerncache_path"]=normpath(self.settings["storedir"]+\
336 "/kerncache/"+self.settings["target_subpath"]+"/")
338 def set_target_path(self):
339 self.settings["target_path"]=normpath(self.settings["storedir"]+\
340 "/builds/"+self.settings["target_subpath"]+".tar.bz2")
341 setup_target_path_resume = pjoin(self.settings["autoresume_path"],
343 if "AUTORESUME" in self.settings and \
344 os.path.exists(setup_target_path_resume):
346 "Resume point detected, skipping target path setup operation..."
348 """ First clean up any existing target stuff """
349 # XXX WTF are we removing the old tarball before we start building the
350 # XXX new one? If the build fails, you don't want to be left with
352 # if os.path.isfile(self.settings["target_path"]):
353 # cmd("rm -f "+self.settings["target_path"],\
354 # "Could not remove existing file: "\
355 # +self.settings["target_path"],env=self.env)
356 touch(setup_target_path_resume)
358 if not os.path.exists(self.settings["storedir"]+"/builds/"):
359 os.makedirs(self.settings["storedir"]+"/builds/")
361 def set_fsscript(self):
362 if self.settings["spec_prefix"]+"/fsscript" in self.settings:
363 self.settings["fsscript"]=\
364 self.settings[self.settings["spec_prefix"]+"/fsscript"]
365 del self.settings[self.settings["spec_prefix"]+"/fsscript"]
368 if self.settings["spec_prefix"]+"/rcadd" in self.settings:
369 self.settings["rcadd"]=\
370 self.settings[self.settings["spec_prefix"]+"/rcadd"]
371 del self.settings[self.settings["spec_prefix"]+"/rcadd"]
374 if self.settings["spec_prefix"]+"/rcdel" in self.settings:
375 self.settings["rcdel"]=\
376 self.settings[self.settings["spec_prefix"]+"/rcdel"]
377 del self.settings[self.settings["spec_prefix"]+"/rcdel"]
380 if self.settings["spec_prefix"]+"/cdtar" in self.settings:
381 self.settings["cdtar"]=\
382 normpath(self.settings[self.settings["spec_prefix"]+"/cdtar"])
383 del self.settings[self.settings["spec_prefix"]+"/cdtar"]
386 if self.settings["spec_prefix"]+"/iso" in self.settings:
387 if self.settings[self.settings["spec_prefix"]+"/iso"].startswith('/'):
388 self.settings["iso"]=\
389 normpath(self.settings[self.settings["spec_prefix"]+"/iso"])
391 # This automatically prepends the build dir to the ISO output path
392 # if it doesn't start with a /
393 self.settings["iso"] = normpath(self.settings["storedir"] + \
394 "/builds/" + self.settings["rel_type"] + "/" + \
395 self.settings[self.settings["spec_prefix"]+"/iso"])
396 del self.settings[self.settings["spec_prefix"]+"/iso"]
398 def set_fstype(self):
399 if self.settings["spec_prefix"]+"/fstype" in self.settings:
400 self.settings["fstype"]=\
401 self.settings[self.settings["spec_prefix"]+"/fstype"]
402 del self.settings[self.settings["spec_prefix"]+"/fstype"]
404 if "fstype" not in self.settings:
405 self.settings["fstype"]="normal"
406 for x in self.valid_values:
407 if x == self.settings["spec_prefix"]+"/fstype":
408 print "\n"+self.settings["spec_prefix"]+\
409 "/fstype is being set to the default of \"normal\"\n"
412 if "fstype" in self.settings:
413 self.valid_values.append("fsops")
414 if self.settings["spec_prefix"]+"/fsops" in self.settings:
415 self.settings["fsops"]=\
416 self.settings[self.settings["spec_prefix"]+"/fsops"]
417 del self.settings[self.settings["spec_prefix"]+"/fsops"]
419 def set_source_path(self):
420 if "SEEDCACHE" in self.settings\
421 and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+\
422 self.settings["source_subpath"]+"/")):
423 self.settings["source_path"]=normpath(self.settings["storedir"]+\
424 "/tmp/"+self.settings["source_subpath"]+"/")
426 self.settings["source_path"]=normpath(self.settings["storedir"]+\
427 "/builds/"+self.settings["source_subpath"]+".tar.bz2")
428 if os.path.isfile(self.settings["source_path"]):
429 # XXX: Is this even necessary if the previous check passes?
430 if os.path.exists(self.settings["source_path"]):
431 self.settings["source_path_hash"]=\
432 generate_hash(self.settings["source_path"],\
433 hash_function=self.settings["hash_function"],\
435 print "Source path set to "+self.settings["source_path"]
436 if os.path.isdir(self.settings["source_path"]):
437 print "\tIf this is not desired, remove this directory or turn off"
438 print "\tseedcache in the options of catalyst.conf the source path"
439 print "\twill then be "+\
440 normpath(self.settings["storedir"]+"/builds/"+\
441 self.settings["source_subpath"]+".tar.bz2\n")
443 def set_dest_path(self):
444 if "root_path" in self.settings:
445 self.settings["destpath"]=normpath(self.settings["chroot_path"]+\
446 self.settings["root_path"])
448 self.settings["destpath"]=normpath(self.settings["chroot_path"])
450 def set_cleanables(self):
451 self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/tmp/*",\
452 "/root/*", self.settings["portdir"]]
454 def set_snapshot_path(self):
455 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
456 "/snapshots/" + self.settings["snapshot_name"] +
457 self.settings["snapshot"] + ".tar.xz")
459 if os.path.exists(self.settings["snapshot_path"]):
460 self.settings["snapshot_path_hash"]=\
461 generate_hash(self.settings["snapshot_path"],\
462 hash_function=self.settings["hash_function"],verbose=False)
464 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
465 "/snapshots/" + self.settings["snapshot_name"] +
466 self.settings["snapshot"] + ".tar.bz2")
468 if os.path.exists(self.settings["snapshot_path"]):
469 self.settings["snapshot_path_hash"]=\
470 generate_hash(self.settings["snapshot_path"],\
471 hash_function=self.settings["hash_function"],verbose=False)
473 def set_snapcache_path(self):
474 if "SNAPCACHE" in self.settings:
475 self.settings["snapshot_cache_path"] = \
476 normpath(self.settings["snapshot_cache"] + "/" +
477 self.settings["snapshot"])
478 self.snapcache_lock=\
479 LockDir(self.settings["snapshot_cache_path"])
480 print "Caching snapshot to "+self.settings["snapshot_cache_path"]
482 def set_chroot_path(self):
484 NOTE: the trailing slash has been removed
485 Things *could* break if you don't use a proper join()
487 self.settings["chroot_path"]=normpath(self.settings["storedir"]+\
488 "/tmp/"+self.settings["target_subpath"])
489 self.chroot_lock=LockDir(self.settings["chroot_path"])
491 def set_autoresume_path(self):
492 self.settings["autoresume_path"] = normpath(pjoin(
493 self.settings["storedir"], "tmp", self.settings["rel_type"],
494 ".autoresume-%s-%s-%s"
495 %(self.settings["target"], self.settings["subarch"],
496 self.settings["version_stamp"])
498 if "AUTORESUME" in self.settings:
499 print "The autoresume path is " + self.settings["autoresume_path"]
500 if not os.path.exists(self.settings["autoresume_path"]):
501 os.makedirs(self.settings["autoresume_path"],0755)
503 def set_controller_file(self):
504 self.settings["controller_file"]=normpath(self.settings["sharedir"]+\
505 "/targets/"+self.settings["target"]+"/"+self.settings["target"]+\
508 def set_iso_volume_id(self):
509 if self.settings["spec_prefix"]+"/volid" in self.settings:
510 self.settings["iso_volume_id"]=\
511 self.settings[self.settings["spec_prefix"]+"/volid"]
512 if len(self.settings["iso_volume_id"])>32:
513 raise CatalystError,\
514 "ISO volume ID must not exceed 32 characters."
516 self.settings["iso_volume_id"]="catalyst "+self.settings["snapshot"]
518 def set_action_sequence(self):
519 """ Default action sequence for run method """
520 self.settings["action_sequence"]=["unpack","unpack_snapshot",\
521 "setup_confdir","portage_overlay",\
522 "base_dirs","bind","chroot_setup","setup_environment",\
523 "run_local","preclean","unbind","clean"]
524 # if "TARBALL" in self.settings or \
525 # "FETCH" not in self.settings:
526 if "FETCH" not in self.settings:
527 self.settings["action_sequence"].append("capture")
528 self.settings["action_sequence"].append("clear_autoresume")
531 if self.settings["spec_prefix"]+"/use" in self.settings:
532 self.settings["use"]=\
533 self.settings[self.settings["spec_prefix"]+"/use"]
534 del self.settings[self.settings["spec_prefix"]+"/use"]
535 if "use" not in self.settings:
536 self.settings["use"]=""
537 if type(self.settings["use"])==types.StringType:
538 self.settings["use"]=self.settings["use"].split()
540 # Force bindist when options ask for it
541 if "BINDIST" in self.settings:
542 self.settings["use"].append("bindist")
544 def set_stage_path(self):
545 self.settings["stage_path"]=normpath(self.settings["chroot_path"])
547 def set_mounts(self):
550 def set_packages(self):
554 if self.settings["spec_prefix"]+"/rm" in self.settings:
555 if type(self.settings[self.settings["spec_prefix"]+\
556 "/rm"])==types.StringType:
557 self.settings[self.settings["spec_prefix"]+"/rm"]=\
558 self.settings[self.settings["spec_prefix"]+"/rm"].split()
560 def set_linuxrc(self):
561 if self.settings["spec_prefix"]+"/linuxrc" in self.settings:
562 if type(self.settings[self.settings["spec_prefix"]+\
563 "/linuxrc"])==types.StringType:
564 self.settings["linuxrc"]=\
565 self.settings[self.settings["spec_prefix"]+"/linuxrc"]
566 del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
568 def set_busybox_config(self):
569 if self.settings["spec_prefix"]+"/busybox_config" in self.settings:
570 if type(self.settings[self.settings["spec_prefix"]+\
571 "/busybox_config"])==types.StringType:
572 self.settings["busybox_config"]=\
573 self.settings[self.settings["spec_prefix"]+"/busybox_config"]
574 del self.settings[self.settings["spec_prefix"]+"/busybox_config"]
576 def set_portage_overlay(self):
577 if "portage_overlay" in self.settings:
578 if type(self.settings["portage_overlay"])==types.StringType:
579 self.settings["portage_overlay"]=\
580 self.settings["portage_overlay"].split()
581 print "portage_overlay directories are set to: \""+\
582 string.join(self.settings["portage_overlay"])+"\""
584 def set_overlay(self):
585 if self.settings["spec_prefix"]+"/overlay" in self.settings:
586 if type(self.settings[self.settings["spec_prefix"]+\
587 "/overlay"])==types.StringType:
588 self.settings[self.settings["spec_prefix"]+"/overlay"]=\
589 self.settings[self.settings["spec_prefix"]+\
592 def set_root_overlay(self):
593 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
594 if type(self.settings[self.settings["spec_prefix"]+\
595 "/root_overlay"])==types.StringType:
596 self.settings[self.settings["spec_prefix"]+"/root_overlay"]=\
597 self.settings[self.settings["spec_prefix"]+\
598 "/root_overlay"].split()
600 def set_root_path(self):
601 """ ROOT= variable for emerges """
602 self.settings["root_path"]="/"
604 def set_valid_build_kernel_vars(self,addlargs):
605 if "boot/kernel" in addlargs:
606 if type(addlargs["boot/kernel"])==types.StringType:
607 loopy=[addlargs["boot/kernel"]]
609 loopy=addlargs["boot/kernel"]
612 self.valid_values.append("boot/kernel/"+x+"/aliases")
613 self.valid_values.append("boot/kernel/"+x+"/config")
614 self.valid_values.append("boot/kernel/"+x+"/console")
615 self.valid_values.append("boot/kernel/"+x+"/extraversion")
616 self.valid_values.append("boot/kernel/"+x+"/gk_action")
617 self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
618 self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
619 self.valid_values.append("boot/kernel/"+x+"/machine_type")
620 self.valid_values.append("boot/kernel/"+x+"/sources")
621 self.valid_values.append("boot/kernel/"+x+"/softlevel")
622 self.valid_values.append("boot/kernel/"+x+"/use")
623 self.valid_values.append("boot/kernel/"+x+"/packages")
624 if "boot/kernel/"+x+"/packages" in addlargs:
625 if type(addlargs["boot/kernel/"+x+\
626 "/packages"])==types.StringType:
627 addlargs["boot/kernel/"+x+"/packages"]=\
628 [addlargs["boot/kernel/"+x+"/packages"]]
630 def set_build_kernel_vars(self):
631 if self.settings["spec_prefix"]+"/gk_mainargs" in self.settings:
632 self.settings["gk_mainargs"]=\
633 self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
634 del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
636 def kill_chroot_pids(self):
637 print "Checking for processes running in chroot and killing them."
640 Force environment variables to be exported so script can see them
642 self.setup_environment()
644 if os.path.exists(self.settings["sharedir"]+\
645 "/targets/support/kill-chroot-pids.sh"):
646 cmd("/bin/bash "+self.settings["sharedir"]+\
647 "/targets/support/kill-chroot-pids.sh",\
648 "kill-chroot-pids script failed.",env=self.env)
650 def mount_safety_check(self):
652 Check and verify that none of our paths in mypath are mounted. We don't
653 want to clean up with things still mounted, and this allows us to check.
654 Returns 1 on ok, 0 on "something is still mounted" case.
657 if not os.path.exists(self.settings["chroot_path"]):
660 print "self.mounts =", self.mounts
661 for x in self.mounts:
662 target = normpath(self.settings["chroot_path"] + self.target_mounts[x])
663 print "mount_safety_check() x =", x, target
664 if not os.path.exists(target):
668 """ Something is still mounted "" """
670 print target + " is still mounted; performing auto-bind-umount...",
671 """ Try to umount stuff ourselves """
674 raise CatalystError, "Auto-unbind failed for " + target
676 print "Auto-unbind successful..."
677 except CatalystError:
678 raise CatalystError, "Unable to auto-unbind " + target
683 unpack_resume = pjoin(self.settings["autoresume_path"], "unpack")
684 clst_unpack_hash=read_from_clst(unpack_resume)
686 if "SEEDCACHE" in self.settings:
687 if os.path.isdir(self.settings["source_path"]):
688 """ SEEDCACHE Is a directory, use rsync """
689 unpack_cmd="rsync -a --delete "+self.settings["source_path"]+\
690 " "+self.settings["chroot_path"]
691 display_msg="\nStarting rsync from "+\
692 self.settings["source_path"]+"\nto "+\
693 self.settings["chroot_path"]+\
694 " (This may take some time) ...\n"
695 error_msg="Rsync of "+self.settings["source_path"]+" to "+\
696 self.settings["chroot_path"]+" failed."
698 """ SEEDCACHE is a not a directory, try untar'ing """
699 print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
700 display_msg="\nStarting tar extract from "+\
701 self.settings["source_path"]+"\nto "+\
702 self.settings["chroot_path"]+\
703 " (This may take some time) ...\n"
704 if "bz2" == self.settings["chroot_path"][-3:]:
705 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
706 self.settings["chroot_path"]
708 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
709 self.settings["chroot_path"]
710 error_msg="Tarball extraction of "+\
711 self.settings["source_path"]+" to "+\
712 self.settings["chroot_path"]+" failed."
714 """ No SEEDCACHE, use tar """
715 display_msg="\nStarting tar extract from "+\
716 self.settings["source_path"]+"\nto "+\
717 self.settings["chroot_path"]+\
718 " (This may take some time) ...\n"
719 if "bz2" == self.settings["chroot_path"][-3:]:
720 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
721 self.settings["chroot_path"]
723 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
724 self.settings["chroot_path"]
725 error_msg="Tarball extraction of "+self.settings["source_path"]+\
726 " to "+self.settings["chroot_path"]+" failed."
728 if "AUTORESUME" in self.settings:
729 if os.path.isdir(self.settings["source_path"]) \
730 and os.path.exists(unpack_resume):
731 """ Autoresume is valid, SEEDCACHE is valid """
733 invalid_snapshot=False
735 elif os.path.isfile(self.settings["source_path"]) \
736 and self.settings["source_path_hash"]==clst_unpack_hash:
737 """ Autoresume is valid, tarball is valid """
739 invalid_snapshot=True
741 elif os.path.isdir(self.settings["source_path"]) \
742 and not os.path.exists(unpack_resume):
743 """ Autoresume is invalid, SEEDCACHE """
745 invalid_snapshot=False
747 elif os.path.isfile(self.settings["source_path"]) \
748 and self.settings["source_path_hash"]!=clst_unpack_hash:
749 """ Autoresume is invalid, tarball """
751 invalid_snapshot=True
753 """ No autoresume, SEEDCACHE """
754 if "SEEDCACHE" in self.settings:
755 """ SEEDCACHE so let's run rsync and let it clean up """
756 if os.path.isdir(self.settings["source_path"]):
758 invalid_snapshot=False
759 elif os.path.isfile(self.settings["source_path"]):
760 """ Tarball so unpack and remove anything already there """
762 invalid_snapshot=True
763 """ No autoresume, no SEEDCACHE """
765 """ Tarball so unpack and remove anything already there """
766 if os.path.isfile(self.settings["source_path"]):
768 invalid_snapshot=True
769 elif os.path.isdir(self.settings["source_path"]):
770 """ We should never reach this, so something is very wrong """
771 raise CatalystError,\
772 "source path is a dir but seedcache is not enabled"
775 self.mount_safety_check()
778 if "AUTORESUME" in self.settings:
779 print "No Valid Resume point detected, cleaning up..."
781 self.clear_autoresume()
784 if not os.path.exists(self.settings["chroot_path"]):
785 os.makedirs(self.settings["chroot_path"])
787 if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
788 os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
790 if "PKGCACHE" in self.settings:
791 if not os.path.exists(self.settings["pkgcache_path"]):
792 os.makedirs(self.settings["pkgcache_path"],0755)
794 if "KERNCACHE" in self.settings:
795 if not os.path.exists(self.settings["kerncache_path"]):
796 os.makedirs(self.settings["kerncache_path"],0755)
799 cmd(unpack_cmd,error_msg,env=self.env)
801 if "source_path_hash" in self.settings:
802 myf=open(unpack_resume,"w")
803 myf.write(self.settings["source_path_hash"])
808 print "Resume point detected, skipping unpack operation..."
810 def unpack_snapshot(self):
812 unpack_portage_resume = pjoin(self.settings["autoresume_path"],
814 snapshot_hash=read_from_clst(unpack_portage_resume)
816 if "SNAPCACHE" in self.settings:
817 snapshot_cache_hash=\
818 read_from_clst(self.settings["snapshot_cache_path"] + "/" +
820 destdir=self.settings["snapshot_cache_path"]
821 if "bz2" == self.settings["chroot_path"][-3:]:
822 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+destdir
824 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+destdir
825 unpack_errmsg="Error unpacking snapshot"
826 cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+\
827 self.settings["snapshot_cache_path"]+\
828 " (This can take a long time)..."
829 cleanup_errmsg="Error removing existing snapshot cache directory."
830 self.snapshot_lock_object=self.snapcache_lock
832 if self.settings["snapshot_path_hash"]==snapshot_cache_hash:
833 print "Valid snapshot cache, skipping unpack of portage tree..."
836 destdir = normpath(self.settings["chroot_path"] + self.settings["portdir"])
837 cleanup_errmsg="Error removing existing snapshot directory."
839 "Cleaning up existing portage tree (This can take a long time)..."
840 if "bz2" == self.settings["chroot_path"][-3:]:
841 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+\
842 self.settings["chroot_path"]+"/usr"
844 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+\
845 self.settings["chroot_path"]+"/usr"
846 unpack_errmsg="Error unpacking snapshot"
848 if "AUTORESUME" in self.settings \
849 and os.path.exists(self.settings["chroot_path"]+\
850 self.settings["portdir"]) \
851 and os.path.exists(unpack_portage_resume) \
852 and self.settings["snapshot_path_hash"] == snapshot_hash:
854 "Valid Resume point detected, skipping unpack of portage tree..."
858 if "SNAPCACHE" in self.settings:
859 self.snapshot_lock_object.write_lock()
860 if os.path.exists(destdir):
862 cleanup_cmd="rm -rf "+destdir
863 cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
864 if not os.path.exists(destdir):
865 os.makedirs(destdir,0755)
867 print "Unpacking portage tree (This can take a long time) ..."
868 cmd(unpack_cmd,unpack_errmsg,env=self.env)
870 if "SNAPCACHE" in self.settings:
871 myf=open(self.settings["snapshot_cache_path"] +
872 "/" + "catalyst-hash","w")
873 myf.write(self.settings["snapshot_path_hash"])
876 print "Setting snapshot autoresume point"
877 myf=open(unpack_portage_resume,"w")
878 myf.write(self.settings["snapshot_path_hash"])
881 if "SNAPCACHE" in self.settings:
882 self.snapshot_lock_object.unlock()
884 def config_profile_link(self):
885 config_protect_link_resume = pjoin(self.settings["autoresume_path"],
886 "config_profile_link")
887 if "AUTORESUME" in self.settings \
888 and os.path.exists(config_protect_link_resume):
890 "Resume point detected, skipping config_profile_link operation..."
892 # TODO: zmedico and I discussed making this a directory and pushing
893 # in a parent file, as well as other user-specified configuration.
894 print "Configuring profile link..."
895 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.profile",\
896 "Error zapping profile link",env=self.env)
897 cmd("mkdir -p "+self.settings["chroot_path"]+"/etc/portage/")
898 cmd("ln -sf ../.." + self.settings["portdir"] + "/profiles/" + \
899 self.settings["target_profile"]+" "+\
900 self.settings["chroot_path"]+"/etc/portage/make.profile",\
901 "Error creating profile link",env=self.env)
902 touch(config_protect_link_resume)
904 def setup_confdir(self):
905 setup_confdir_resume = pjoin(self.settings["autoresume_path"],
907 if "AUTORESUME" in self.settings \
908 and os.path.exists(setup_confdir_resume):
909 print "Resume point detected, skipping setup_confdir operation..."
911 if "portage_confdir" in self.settings:
912 print "Configuring /etc/portage..."
913 cmd("rsync -a "+self.settings["portage_confdir"]+"/ "+\
914 self.settings["chroot_path"]+"/etc/portage/",\
915 "Error copying /etc/portage",env=self.env)
916 touch(setup_confdir_resume)
918 def portage_overlay(self):
919 """ We copy the contents of our overlays to /usr/local/portage """
920 if "portage_overlay" in self.settings:
921 for x in self.settings["portage_overlay"]:
922 if os.path.exists(x):
923 print "Copying overlay dir " +x
924 cmd("mkdir -p "+self.settings["chroot_path"]+\
925 self.settings["local_overlay"],\
926 "Could not make portage_overlay dir",env=self.env)
927 cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+\
928 self.settings["local_overlay"],\
929 "Could not copy portage_overlay",env=self.env)
931 def root_overlay(self):
932 """ Copy over the root_overlay """
933 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
934 for x in self.settings[self.settings["spec_prefix"]+\
936 if os.path.exists(x):
937 print "Copying root_overlay: "+x
938 cmd("rsync -a "+x+"/ "+\
939 self.settings["chroot_path"],\
940 self.settings["spec_prefix"]+"/root_overlay: "+x+\
941 " copy failed.",env=self.env)
947 for x in self.mounts:
948 #print "bind(); x =", x
949 target = normpath(self.settings["chroot_path"] + self.target_mounts[x])
950 if not os.path.exists(target):
951 os.makedirs(target, 0755)
953 if not os.path.exists(self.mountmap[x]):
954 if self.mountmap[x] not in ["tmpfs", "shmfs"]:
955 os.makedirs(self.mountmap[x], 0755)
958 #print "bind(); src =", src
959 if "SNAPCACHE" in self.settings and x == "portdir":
960 self.snapshot_lock_object.read_lock()
961 if os.uname()[0] == "FreeBSD":
963 cmd = "mount -t devfs none " + target
964 retval=os.system(cmd)
966 cmd = "mount_nullfs " + src + " " + target
967 retval=os.system(cmd)
970 if "var_tmpfs_portage" in self.settings:
971 cmd = "mount -t tmpfs -o size=" + \
972 self.settings["var_tmpfs_portage"] + "G " + \
974 retval=os.system(cmd)
976 cmd = "mount -t tmpfs -o noexec,nosuid,nodev shm " + target
977 retval=os.system(cmd)
979 cmd = "mount --bind " + src + " " + target
980 #print "bind(); cmd =", cmd
981 retval=os.system(cmd)
984 raise CatalystError,"Couldn't bind mount " + src
988 mypath=self.settings["chroot_path"]
989 myrevmounts=self.mounts[:]
990 myrevmounts.reverse()
991 """ Unmount in reverse order for nested bind-mounts """
992 for x in myrevmounts:
993 target = normpath(mypath + self.target_mounts[x])
994 if not os.path.exists(target):
997 if not ismount(target):
1000 retval=os.system("umount " + target)
1003 warn("First attempt to unmount: " + target + " failed.")
1004 warn("Killing any pids still running in the chroot")
1006 self.kill_chroot_pids()
1008 retval2 = os.system("umount " + target)
1011 warn("Couldn't umount bind mount: " + target)
1013 if "SNAPCACHE" in self.settings and x == "/usr/portage":
1016 It's possible the snapshot lock object isn't created yet.
1017 This is because mount safety check calls unbind before the
1018 target is fully initialized
1020 self.snapshot_lock_object.unlock()
1025 if any bind mounts really failed, then we need to raise
1026 this to potentially prevent an upcoming bash stage cleanup script
1027 from wiping our bind mounts.
1029 raise CatalystError,\
1030 "Couldn't umount one or more bind-mounts; aborting for safety."
1032 def chroot_setup(self):
1033 self.makeconf=read_makeconf(self.settings["chroot_path"]+\
1034 "/etc/portage/make.conf")
1035 self.override_cbuild()
1036 self.override_chost()
1037 self.override_cflags()
1038 self.override_cxxflags()
1039 self.override_ldflags()
1040 chroot_setup_resume = pjoin(self.settings["autoresume_path"],
1042 if "AUTORESUME" in self.settings and os.path.exists(chroot_setup_resume):
1043 print "Resume point detected, skipping chroot_setup operation..."
1045 print "Setting up chroot..."
1047 #self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/portage/make.conf")
1049 cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
1050 "Could not copy resolv.conf into place.",env=self.env)
1052 """ Copy over the envscript, if applicable """
1053 if "ENVSCRIPT" in self.settings:
1054 if not os.path.exists(self.settings["ENVSCRIPT"]):
1055 raise CatalystError,\
1056 "Can't find envscript "+self.settings["ENVSCRIPT"]
1058 print "\nWarning!!!!"
1059 print "\tOverriding certain env variables may cause catastrophic failure."
1060 print "\tIf your build fails look here first as the possible problem."
1061 print "\tCatalyst assumes you know what you are doing when setting"
1062 print "\t\tthese variables."
1063 print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
1064 print "\tYou have been warned\n"
1066 cmd("cp "+self.settings["ENVSCRIPT"]+" "+\
1067 self.settings["chroot_path"]+"/tmp/envscript",\
1068 "Could not copy envscript into place.",env=self.env)
1071 Copy over /etc/hosts from the host in case there are any
1072 specialties in there
1074 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
1075 cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+\
1076 self.settings["chroot_path"]+"/etc/hosts.catalyst",\
1077 "Could not backup /etc/hosts",env=self.env)
1078 cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts",\
1079 "Could not copy /etc/hosts",env=self.env)
1081 """ Modify and write out make.conf (for the chroot) """
1082 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.conf",\
1083 "Could not remove "+self.settings["chroot_path"]+\
1084 "/etc/portage/make.conf",env=self.env)
1085 myf=open(self.settings["chroot_path"]+"/etc/portage/make.conf","w")
1086 myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
1087 myf.write("# Please consult /usr/share/portage/config/make.conf.example for a more\n# detailed example.\n")
1088 if "CFLAGS" in self.settings:
1089 myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
1090 if "CXXFLAGS" in self.settings:
1091 if self.settings["CXXFLAGS"]!=self.settings["CFLAGS"]:
1092 myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
1094 myf.write('CXXFLAGS="${CFLAGS}"\n')
1096 myf.write('CXXFLAGS="${CFLAGS}"\n')
1098 if "LDFLAGS" in self.settings:
1099 myf.write("# LDFLAGS is unsupported. USE AT YOUR OWN RISK!\n")
1100 myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
1101 if "CBUILD" in self.settings:
1102 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")
1103 myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
1105 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")
1106 myf.write('CHOST="'+self.settings["CHOST"]+'"\n')
1108 """ Figure out what our USE vars are for building """
1110 if "HOSTUSE" in self.settings:
1111 myusevars.extend(self.settings["HOSTUSE"])
1113 if "use" in self.settings:
1114 myusevars.extend(self.settings["use"])
1117 myf.write("# These are the USE flags that were used in addition to what is provided by the\n# profile used for building.\n")
1118 myusevars = sorted(set(myusevars))
1119 myf.write('USE="'+string.join(myusevars)+'"\n')
1120 if '-*' in myusevars:
1121 print "\nWarning!!! "
1122 print "\tThe use of -* in "+self.settings["spec_prefix"]+\
1123 "/use will cause portage to ignore"
1124 print "\tpackage.use in the profile and portage_confdir. You've been warned!"
1126 myf.write('PORTDIR="%s"\n' % self.settings['portdir'])
1127 myf.write('DISTDIR="%s"\n' % self.settings['distdir'])
1128 myf.write('PKGDIR="%s"\n' % self.settings['packagedir'])
1130 """ Setup the portage overlay """
1131 if "portage_overlay" in self.settings:
1132 myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
1135 cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
1136 self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
1137 "Could not backup /etc/portage/make.conf",env=self.env)
1138 touch(chroot_setup_resume)
1141 fsscript_resume = pjoin(self.settings["autoresume_path"], "fsscript")
1142 if "AUTORESUME" in self.settings and os.path.exists(fsscript_resume):
1143 print "Resume point detected, skipping fsscript operation..."
1145 if "fsscript" in self.settings:
1146 if os.path.exists(self.settings["controller_file"]):
1147 cmd("/bin/bash "+self.settings["controller_file"]+\
1148 " fsscript","fsscript script failed.",env=self.env)
1149 touch(fsscript_resume)
1152 rcupdate_resume = pjoin(self.settings["autoresume_path"], "rcupdate")
1153 if "AUTORESUME" in self.settings \
1154 and os.path.exists(rcupdate_resume):
1155 print "Resume point detected, skipping rcupdate operation..."
1157 if os.path.exists(self.settings["controller_file"]):
1158 cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
1159 "rc-update script failed.",env=self.env)
1160 touch(rcupdate_resume)
1163 clean_resume = pjoin(self.settings["autoresume_path"], "clean")
1164 if "AUTORESUME" in self.settings \
1165 and os.path.exists(clean_resume):
1166 print "Resume point detected, skipping clean operation..."
1168 for x in self.settings["cleanables"]:
1169 print "Cleaning chroot: "+x+"... "
1170 cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
1173 """ Put /etc/hosts back into place """
1174 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
1175 cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
1176 self.settings["chroot_path"]+"/etc/hosts",\
1177 "Could not replace /etc/hosts",env=self.env)
1179 """ Remove our overlay """
1180 if os.path.exists(self.settings["chroot_path"] + self.settings["local_overlay"]):
1181 cmd("rm -rf " + self.settings["chroot_path"] + self.settings["local_overlay"],
1182 "Could not remove " + self.settings["local_overlay"], env=self.env)
1183 cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
1184 "/etc/portage/make.conf",\
1185 "Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
1187 """ Clean up old and obsoleted files in /etc """
1188 if os.path.exists(self.settings["stage_path"]+"/etc"):
1189 cmd("find "+self.settings["stage_path"]+\
1190 "/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
1191 "Could not remove stray files in /etc",env=self.env)
1193 if os.path.exists(self.settings["controller_file"]):
1194 cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
1195 "clean script failed.",env=self.env)
1199 empty_resume = pjoin(self.settings["autoresume_path"], "empty")
1200 if "AUTORESUME" in self.settings and os.path.exists(empty_resume):
1201 print "Resume point detected, skipping empty operation..."
1203 if self.settings["spec_prefix"]+"/empty" in self.settings:
1204 if type(self.settings[self.settings["spec_prefix"]+\
1205 "/empty"])==types.StringType:
1206 self.settings[self.settings["spec_prefix"]+"/empty"]=\
1207 self.settings[self.settings["spec_prefix"]+\
1209 for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
1210 myemp=self.settings["destpath"]+x
1211 if not os.path.isdir(myemp) or os.path.islink(myemp):
1212 print x,"not a directory or does not exist, skipping 'empty' operation."
1214 print "Emptying directory",x
1216 stat the dir, delete the dir, recreate the dir and set
1217 the proper perms and ownership
1219 mystat=os.stat(myemp)
1220 shutil.rmtree(myemp)
1221 os.makedirs(myemp,0755)
1222 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1223 os.chmod(myemp,mystat[ST_MODE])
1227 remove_resume = pjoin(self.settings["autoresume_path"], "remove")
1228 if "AUTORESUME" in self.settings and os.path.exists(remove_resume):
1229 print "Resume point detected, skipping remove operation..."
1231 if self.settings["spec_prefix"]+"/rm" in self.settings:
1232 for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
1234 We're going to shell out for all these cleaning
1235 operations, so we get easy glob handling.
1237 print "livecd: removing "+x
1238 os.system("rm -rf "+self.settings["chroot_path"]+x)
1240 if os.path.exists(self.settings["controller_file"]):
1241 cmd("/bin/bash "+self.settings["controller_file"]+\
1242 " clean","Clean failed.",env=self.env)
1243 touch(remove_resume)
1249 preclean_resume = pjoin(self.settings["autoresume_path"], "preclean")
1250 if "AUTORESUME" in self.settings and os.path.exists(preclean_resume):
1251 print "Resume point detected, skipping preclean operation..."
1254 if os.path.exists(self.settings["controller_file"]):
1255 cmd("/bin/bash "+self.settings["controller_file"]+\
1256 " preclean","preclean script failed.",env=self.env)
1257 touch(preclean_resume)
1261 raise CatalystError, "Build failed, could not execute preclean"
1264 capture_resume = pjoin(self.settings["autoresume_path"], "capture")
1265 if "AUTORESUME" in self.settings and os.path.exists(capture_resume):
1266 print "Resume point detected, skipping capture operation..."
1268 """ Capture target in a tarball """
1269 mypath=self.settings["target_path"].split("/")
1270 """ Remove filename from path """
1271 mypath=string.join(mypath[:-1],"/")
1273 """ Now make sure path exists """
1274 if not os.path.exists(mypath):
1277 print "Creating stage tarball..."
1279 cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
1280 self.settings["stage_path"]+" .",\
1281 "Couldn't create stage tarball",env=self.env)
1283 self.gen_contents_file(self.settings["target_path"])
1284 self.gen_digest_file(self.settings["target_path"])
1286 touch(capture_resume)
1288 def run_local(self):
1289 run_local_resume = pjoin(self.settings["autoresume_path"], "run_local")
1290 if "AUTORESUME" in self.settings and os.path.exists(run_local_resume):
1291 print "Resume point detected, skipping run_local operation..."
1294 if os.path.exists(self.settings["controller_file"]):
1295 cmd("/bin/bash "+self.settings["controller_file"]+" run",\
1296 "run script failed.",env=self.env)
1297 touch(run_local_resume)
1299 except CatalystError:
1301 raise CatalystError,"Stage build aborting due to error."
1303 def setup_environment(self):
1305 Modify the current environment. This is an ugly hack that should be
1306 fixed. We need this to use the os.system() call since we can't
1307 specify our own environ
1309 for x in self.settings.keys():
1310 """ Sanitize var names by doing "s|/-.|_|g" """
1311 varname="clst_"+string.replace(x,"/","_")
1312 varname=string.replace(varname,"-","_")
1313 varname=string.replace(varname,".","_")
1314 if type(self.settings[x])==types.StringType:
1315 """ Prefix to prevent namespace clashes """
1316 #os.environ[varname]=self.settings[x]
1317 self.env[varname]=self.settings[x]
1318 elif type(self.settings[x])==types.ListType:
1319 #os.environ[varname]=string.join(self.settings[x])
1320 self.env[varname]=string.join(self.settings[x])
1321 elif type(self.settings[x])==types.BooleanType:
1322 if self.settings[x]:
1323 self.env[varname]="true"
1325 self.env[varname]="false"
1326 if "makeopts" in self.settings:
1327 self.env["MAKEOPTS"]=self.settings["makeopts"]
1330 self.chroot_lock.write_lock()
1332 """ Kill any pids in the chroot "" """
1333 self.kill_chroot_pids()
1335 """ Check for mounts right away and abort if we cannot unmount them """
1336 self.mount_safety_check()
1338 if "CLEAR_AUTORESUME" in self.settings:
1339 self.clear_autoresume()
1341 if "PURGETMPONLY" in self.settings:
1345 if "PURGEONLY" in self.settings:
1349 if "PURGE" in self.settings:
1352 for x in self.settings["action_sequence"]:
1353 print "--- Running action sequence: "+x
1356 apply(getattr(self,x))
1358 self.mount_safety_check()
1361 self.chroot_lock.unlock()
1364 unmerge_resume = pjoin(self.settings["autoresume_path"], "unmerge")
1365 if "AUTORESUME" in self.settings and os.path.exists(unmerge_resume):
1366 print "Resume point detected, skipping unmerge operation..."
1368 if self.settings["spec_prefix"]+"/unmerge" in self.settings:
1369 if type(self.settings[self.settings["spec_prefix"]+\
1370 "/unmerge"])==types.StringType:
1371 self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
1372 [self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1374 self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1376 for x in range(0,len(myunmerge)):
1378 Surround args with quotes for passing to bash, allows
1379 things like "<" to remain intact
1381 myunmerge[x]="'"+myunmerge[x]+"'"
1382 myunmerge=string.join(myunmerge)
1384 """ Before cleaning, unmerge stuff """
1386 cmd("/bin/bash "+self.settings["controller_file"]+\
1387 " unmerge "+ myunmerge,"Unmerge script failed.",\
1389 print "unmerge shell script"
1390 except CatalystError:
1393 touch(unmerge_resume)
1395 def target_setup(self):
1396 target_setup_resume = pjoin(self.settings["autoresume_path"],
1398 if "AUTORESUME" in self.settings and os.path.exists(target_setup_resume):
1399 print "Resume point detected, skipping target_setup operation..."
1401 print "Setting up filesystems per filesystem type"
1402 cmd("/bin/bash "+self.settings["controller_file"]+\
1403 " target_image_setup "+ self.settings["target_path"],\
1404 "target_image_setup script failed.",env=self.env)
1405 touch(target_setup_resume)
1407 def setup_overlay(self):
1408 setup_overlay_resume = pjoin(self.settings["autoresume_path"],
1410 if "AUTORESUME" in self.settings and \
1411 os.path.exists(setup_overlay_resume):
1412 print "Resume point detected, skipping setup_overlay operation..."
1414 if self.settings["spec_prefix"]+"/overlay" in self.settings:
1415 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
1416 if os.path.exists(x):
1417 cmd("rsync -a "+x+"/ "+\
1418 self.settings["target_path"],\
1419 self.settings["spec_prefix"]+"overlay: "+x+\
1420 " copy failed.",env=self.env)
1421 touch(setup_overlay_resume)
1423 def create_iso(self):
1424 create_iso_resume = pjoin(self.settings["autoresume_path"], "create_iso")
1425 if "AUTORESUME" in self.settings and os.path.exists(create_iso_resume):
1426 print "Resume point detected, skipping create_iso operation..."
1428 """ Create the ISO """
1429 if "iso" in self.settings:
1430 cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1431 self.settings["iso"],"ISO creation script failed.",\
1433 self.gen_contents_file(self.settings["iso"])
1434 self.gen_digest_file(self.settings["iso"])
1435 touch(create_iso_resume)
1437 print "WARNING: livecd/iso was not defined."
1438 print "An ISO Image will not be created."
1440 def build_packages(self):
1441 build_packages_resume = pjoin(self.settings["autoresume_path"],
1443 if "AUTORESUME" in self.settings and \
1444 os.path.exists(build_packages_resume):
1445 print "Resume point detected, skipping build_packages operation..."
1447 if self.settings["spec_prefix"]+"/packages" in self.settings:
1448 if "AUTORESUME" in self.settings \
1449 and os.path.exists(self.settings["autoresume_path"]+\
1451 print "Resume point detected, skipping build_packages operation..."
1454 list_bashify(self.settings[self.settings["spec_prefix"]\
1457 cmd("/bin/bash "+self.settings["controller_file"]+\
1458 " build_packages "+mypack,\
1459 "Error in attempt to build packages",env=self.env)
1460 touch(build_packages_resume)
1461 except CatalystError:
1463 raise CatalystError,self.settings["spec_prefix"]+\
1464 "build aborting due to error."
1466 def build_kernel(self):
1467 "Build all configured kernels"
1468 build_kernel_resume = pjoin(self.settings["autoresume_path"],
1470 if "AUTORESUME" in self.settings and os.path.exists(build_kernel_resume):
1471 print "Resume point detected, skipping build_kernel operation..."
1473 if "boot/kernel" in self.settings:
1475 mynames=self.settings["boot/kernel"]
1476 if type(mynames)==types.StringType:
1479 Execute the script that sets up the kernel build environment
1481 cmd("/bin/bash "+self.settings["controller_file"]+\
1482 " pre-kmerge ","Runscript pre-kmerge failed",\
1484 for kname in mynames:
1485 self._build_kernel(kname=kname)
1486 touch(build_kernel_resume)
1487 except CatalystError:
1489 raise CatalystError,\
1490 "build aborting due to kernel build error."
1492 def _build_kernel(self, kname):
1493 "Build a single configured kernel by name"
1494 kname_resume = pjoin(self.settings["autoresume_path"],
1495 "build_kernel_" + kname)
1496 if "AUTORESUME" in self.settings and os.path.exists(kname_resume):
1497 print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1499 self._copy_kernel_config(kname=kname)
1502 If we need to pass special options to the bootloader
1503 for this kernel put them into the environment
1505 if "boot/kernel/"+kname+"/kernelopts" in self.settings:
1506 myopts=self.settings["boot/kernel/"+kname+\
1509 if type(myopts) != types.StringType:
1510 myopts = string.join(myopts)
1511 self.env[kname+"_kernelopts"]=myopts
1514 self.env[kname+"_kernelopts"]=""
1516 if "boot/kernel/"+kname+"/extraversion" not in self.settings:
1517 self.settings["boot/kernel/"+kname+\
1520 self.env["clst_kextraversion"]=\
1521 self.settings["boot/kernel/"+kname+\
1524 self._copy_initramfs_overlay(kname=kname)
1526 """ Execute the script that builds the kernel """
1527 cmd("/bin/bash "+self.settings["controller_file"]+\
1529 "Runscript kernel build failed",env=self.env)
1531 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1532 if os.path.exists(self.settings["chroot_path"]+\
1533 "/tmp/initramfs_overlay/"):
1534 print "Cleaning up temporary overlay dir"
1535 cmd("rm -R "+self.settings["chroot_path"]+\
1536 "/tmp/initramfs_overlay/",env=self.env)
1541 Execute the script that cleans up the kernel build
1544 cmd("/bin/bash "+self.settings["controller_file"]+\
1546 "Runscript post-kmerge failed",env=self.env)
1548 def _copy_kernel_config(self, kname):
1549 if "boot/kernel/"+kname+"/config" in self.settings:
1550 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1552 raise CatalystError,\
1553 "Can't find kernel config: "+\
1554 self.settings["boot/kernel/"+kname+\
1558 cmd("cp "+self.settings["boot/kernel/"+kname+\
1560 self.settings["chroot_path"]+"/var/tmp/"+\
1562 "Couldn't copy kernel config: "+\
1563 self.settings["boot/kernel/"+kname+\
1564 "/config"],env=self.env)
1566 except CatalystError:
1569 def _copy_initramfs_overlay(self, kname):
1570 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1571 if os.path.exists(self.settings["boot/kernel/"+\
1572 kname+"/initramfs_overlay"]):
1573 print "Copying initramfs_overlay dir "+\
1574 self.settings["boot/kernel/"+kname+\
1575 "/initramfs_overlay"]
1578 self.settings["chroot_path"]+\
1579 "/tmp/initramfs_overlay/"+\
1580 self.settings["boot/kernel/"+kname+\
1581 "/initramfs_overlay"],env=self.env)
1583 cmd("cp -R "+self.settings["boot/kernel/"+\
1584 kname+"/initramfs_overlay"]+"/* "+\
1585 self.settings["chroot_path"]+\
1586 "/tmp/initramfs_overlay/"+\
1587 self.settings["boot/kernel/"+kname+\
1588 "/initramfs_overlay"],env=self.env)
1590 def bootloader(self):
1591 bootloader_resume = pjoin(self.settings["autoresume_path"], "bootloader")
1592 if "AUTORESUME" in self.settings and os.path.exists(bootloader_resume):
1593 print "Resume point detected, skipping bootloader operation..."
1596 cmd("/bin/bash "+self.settings["controller_file"]+\
1597 " bootloader " + self.settings["target_path"],\
1598 "Bootloader script failed.",env=self.env)
1599 touch(bootloader_resume)
1600 except CatalystError:
1602 raise CatalystError,"Script aborting due to error."
1604 def livecd_update(self):
1605 livecd_update_resume = pjoin(self.settings["autoresume_path"],
1607 if "AUTORESUME" in self.settings \
1608 and os.path.exists(livecd_update_resume):
1609 print "Resume point detected, skipping build_packages operation..."
1612 cmd("/bin/bash "+self.settings["controller_file"]+\
1613 " livecd-update","livecd-update failed.",env=self.env)
1614 touch(livecd_update_resume)
1616 except CatalystError:
1618 raise CatalystError,"build aborting due to livecd_update error."
1620 def clear_chroot(self):
1621 myemp=self.settings["chroot_path"]
1622 if os.path.isdir(myemp):
1623 print "Emptying directory",myemp
1625 stat the dir, delete the dir, recreate the dir and set
1626 the proper perms and ownership
1628 mystat=os.stat(myemp)
1629 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1630 """ There's no easy way to change flags recursively in python """
1631 if os.uname()[0] == "FreeBSD":
1632 os.system("chflags -R noschg "+myemp)
1633 shutil.rmtree(myemp)
1634 os.makedirs(myemp,0755)
1635 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1636 os.chmod(myemp,mystat[ST_MODE])
1638 def clear_packages(self):
1639 if "PKGCACHE" in self.settings:
1640 print "purging the pkgcache ..."
1642 myemp=self.settings["pkgcache_path"]
1643 if os.path.isdir(myemp):
1644 print "Emptying directory",myemp
1646 stat the dir, delete the dir, recreate the dir and set
1647 the proper perms and ownership
1649 mystat=os.stat(myemp)
1650 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1651 shutil.rmtree(myemp)
1652 os.makedirs(myemp,0755)
1653 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1654 os.chmod(myemp,mystat[ST_MODE])
1656 def clear_kerncache(self):
1657 if "KERNCACHE" in self.settings:
1658 print "purging the kerncache ..."
1660 myemp=self.settings["kerncache_path"]
1661 if os.path.isdir(myemp):
1662 print "Emptying directory",myemp
1664 stat the dir, delete the dir, recreate the dir and set
1665 the proper perms and ownership
1667 mystat=os.stat(myemp)
1668 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1669 shutil.rmtree(myemp)
1670 os.makedirs(myemp,0755)
1671 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1672 os.chmod(myemp,mystat[ST_MODE])
1674 def clear_autoresume(self):
1675 """ Clean resume points since they are no longer needed """
1676 if "AUTORESUME" in self.settings:
1677 print "Removing AutoResume Points: ..."
1678 myemp=self.settings["autoresume_path"]
1679 if os.path.isdir(myemp):
1680 if "AUTORESUME" in self.settings:
1681 print "Emptying directory",myemp
1683 stat the dir, delete the dir, recreate the dir and set
1684 the proper perms and ownership
1686 mystat=os.stat(myemp)
1687 if os.uname()[0] == "FreeBSD":
1688 cmd("chflags -R noschg "+myemp,\
1689 "Could not remove immutable flag for file "\
1691 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1692 shutil.rmtree(myemp)
1693 os.makedirs(myemp,0755)
1694 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1695 os.chmod(myemp,mystat[ST_MODE])
1697 def gen_contents_file(self,file):
1698 if os.path.exists(file+".CONTENTS"):
1699 os.remove(file+".CONTENTS")
1700 if "contents" in self.settings:
1701 if os.path.exists(file):
1702 myf=open(file+".CONTENTS","w")
1704 for i in self.settings["contents"].split():
1709 contents=generate_contents(file,contents_function=j,\
1710 verbose="VERBOSE" in self.settings)
1715 def gen_digest_file(self,file):
1716 if os.path.exists(file+".DIGESTS"):
1717 os.remove(file+".DIGESTS")
1718 if "digests" in self.settings:
1719 if os.path.exists(file):
1720 myf=open(file+".DIGESTS","w")
1722 for i in self.settings["digests"].split():
1726 for f in [file, file+'.CONTENTS']:
1727 if os.path.exists(f):
1729 for k in hash_map.keys():
1730 hash=generate_hash(f,hash_function=k,verbose=\
1731 "VERBOSE" in self.settings)
1735 hash=generate_hash(f,hash_function=j,verbose=\
1736 "VERBOSE" in self.settings)
1741 countdown(10,"Purging Caches ...")
1742 if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
1743 print "clearing autoresume ..."
1744 self.clear_autoresume()
1746 print "clearing chroot ..."
1749 if "PURGETMPONLY" not in self.settings:
1750 print "clearing package cache ..."
1751 self.clear_packages()
1753 print "clearing kerncache ..."
1754 self.clear_kerncache()
1756 # vim: ts=4 sw=4 sta et sts=4 ai