1 import os,string,imp,types,shutil
2 from catalyst_support import *
3 from generic_target import *
7 class generic_stage_target(generic_target):
9 This class does all of the chroot setup, copying of files, etc. It is
10 the driver class for pretty much everything that Catalyst does.
12 def __init__(self,myspec,addlargs):
13 self.required_values.extend(["version_stamp","target","subarch",\
14 "rel_type","profile","snapshot","source_subpath"])
16 self.valid_values.extend(["version_stamp","target","subarch",\
17 "rel_type","profile","snapshot","source_subpath","portage_confdir",\
18 "cflags","cxxflags","ldflags","cbuild","hostuse","portage_overlay",\
19 "distcc_hosts","makeopts","pkgcache_path","kerncache_path"])
21 self.set_valid_build_kernel_vars(addlargs)
22 generic_target.__init__(self,myspec,addlargs)
25 The semantics of subarchmap and machinemap changed a bit in 2.0.3 to
26 work better with vapier's CBUILD stuff. I've removed the "monolithic"
27 machinemap from this file and split up its contents amongst the
28 various arch/foo.py files.
30 When register() is called on each module in the arch/ dir, it now
31 returns a tuple instead of acting on the subarchmap dict that is
32 passed to it. The tuple contains the values that were previously
33 added to subarchmap as well as a new list of CHOSTs that go along
34 with that arch. This allows us to build machinemap on the fly based
35 on the keys in subarchmap and the values of the 2nd list returned
38 Also, after talking with vapier. I have a slightly better idea of what
39 certain variables are used for and what they should be set to. Neither
40 'buildarch' or 'hostarch' are used directly, so their value doesn't
41 really matter. They are just compared to determine if we are
42 cross-compiling. Because of this, they are just set to the name of the
43 module in arch/ that the subarch is part of to make things simpler.
44 The entire build process is still based off of 'subarch' like it was
51 for x in [x[:-3] for x in os.listdir(self.settings["sharedir"]+\
52 "/arch/") if x.endswith(".py")]:
54 fh=open(self.settings["sharedir"]+"/arch/"+x+".py")
56 This next line loads the plugin as a module and assigns it to
59 self.archmap[x]=imp.load_module(x,fh,"arch/"+x+\
60 ".py",(".py","r",imp.PY_SOURCE))
62 This next line registers all the subarches supported in the
65 tmpsubarchmap, tmpmachinemap = self.archmap[x].register()
66 self.subarchmap.update(tmpsubarchmap)
67 for machine in tmpmachinemap:
68 machinemap[machine] = x
69 for subarch in tmpsubarchmap:
70 machinemap[subarch] = x
74 This message should probably change a bit, since everything in
75 the dir should load just fine. If it doesn't, it's probably a
76 syntax error in the module
78 msg("Can't find/load "+x+".py plugin in "+\
79 self.settings["sharedir"]+"/arch/")
81 if "chost" in self.settings:
82 hostmachine = self.settings["chost"].split("-")[0]
83 if hostmachine not in machinemap:
84 raise CatalystError, "Unknown host machine type "+hostmachine
85 self.settings["hostarch"]=machinemap[hostmachine]
87 hostmachine = self.settings["subarch"]
88 if hostmachine in machinemap:
89 hostmachine = machinemap[hostmachine]
90 self.settings["hostarch"]=hostmachine
91 if "cbuild" in self.settings:
92 buildmachine = self.settings["cbuild"].split("-")[0]
94 buildmachine = os.uname()[4]
95 if buildmachine not in machinemap:
96 raise CatalystError, "Unknown build machine type "+buildmachine
97 self.settings["buildarch"]=machinemap[buildmachine]
98 self.settings["crosscompile"]=(self.settings["hostarch"]!=\
99 self.settings["buildarch"])
101 """ Call arch constructor, pass our settings """
103 self.arch=self.subarchmap[self.settings["subarch"]](self.settings)
105 print "Invalid subarch: "+self.settings["subarch"]
106 print "Choose one of the following:",
107 for x in self.subarchmap:
112 print "Using target:",self.settings["target"]
113 """ Print a nice informational message """
114 if self.settings["buildarch"]==self.settings["hostarch"]:
115 print "Building natively for",self.settings["hostarch"]
116 elif self.settings["crosscompile"]:
117 print "Cross-compiling on",self.settings["buildarch"],\
118 "for different machine type",self.settings["hostarch"]
120 print "Building on",self.settings["buildarch"],\
121 "for alternate personality type",self.settings["hostarch"]
123 """ This must be set first as other set_ options depend on this """
124 self.set_spec_prefix()
126 """ Define all of our core variables """
127 self.set_target_profile()
128 self.set_target_subpath()
129 self.set_source_subpath()
132 self.set_snapshot_path()
134 self.set_source_path()
135 self.set_snapcache_path()
136 self.set_chroot_path()
137 self.set_autoresume_path()
139 self.set_stage_path()
140 self.set_target_path()
142 self.set_controller_file()
143 self.set_action_sequence()
145 self.set_cleanables()
146 self.set_iso_volume_id()
147 self.set_build_kernel_vars()
149 self.set_install_mask()
159 self.set_busybox_config()
161 self.set_portage_overlay()
162 self.set_root_overlay()
165 This next line checks to make sure that the specified variables exist
169 file_locate(self.settings,["source_path","snapshot_path","distdir"],\
171 """ If we are using portage_confdir, check that as well. """
172 if "portage_confdir" in self.settings:
173 file_locate(self.settings,["portage_confdir"],expand=0)
175 """ Setup our mount points """
176 if "SNAPCACHE" in self.settings:
177 self.mounts=["/proc","/dev","/usr/portage","/usr/portage/distfiles","/var/tmp/portage"]
178 self.mountmap={"/proc":"/proc","/dev":"/dev","/dev/pts":"/dev/pts",\
179 "/usr/portage":self.settings["snapshot_cache_path"]+"/portage",\
180 "/usr/portage/distfiles":self.settings["distdir"],"/var/tmp/portage":"tmpfs"}
182 self.mounts=["/proc","/dev","/usr/portage/distfiles","/var/tmp/portage"]
183 self.mountmap={"/proc":"/proc","/dev":"/dev","/dev/pts":"/dev/pts",\
184 "/usr/portage/distfiles":self.settings["distdir"],"/var/tmp/portage":"tmpfs"}
185 if os.uname()[0] == "Linux":
186 self.mounts.append("/dev/pts")
191 Configure any user specified options (either in catalyst.conf or on
194 if "PKGCACHE" in self.settings:
195 self.set_pkgcache_path()
196 print "Location of the package cache is "+\
197 self.settings["pkgcache_path"]
198 self.mounts.append("/usr/portage/packages")
199 self.mountmap["/usr/portage/packages"]=\
200 self.settings["pkgcache_path"]
202 if "KERNCACHE" in self.settings:
203 self.set_kerncache_path()
204 print "Location of the kerncache is "+\
205 self.settings["kerncache_path"]
206 self.mounts.append("/tmp/kerncache")
207 self.mountmap["/tmp/kerncache"]=self.settings["kerncache_path"]
209 if "CCACHE" in self.settings:
210 if "CCACHE_DIR" in os.environ:
211 ccdir=os.environ["CCACHE_DIR"]
212 del os.environ["CCACHE_DIR"]
214 ccdir="/root/.ccache"
215 if not os.path.isdir(ccdir):
216 raise CatalystError,\
217 "Compiler cache support can't be enabled (can't find "+\
219 self.mounts.append("/var/tmp/ccache")
220 self.mountmap["/var/tmp/ccache"]=ccdir
221 """ for the chroot: """
222 self.env["CCACHE_DIR"]="/var/tmp/ccache"
224 if "ICECREAM" in self.settings:
225 self.mounts.append("/var/cache/icecream")
226 self.mountmap["/var/cache/icecream"]="/var/cache/icecream"
227 self.env["PATH"]="/usr/lib/icecc/bin:"+self.env["PATH"]
229 if "port_logdir" in self.settings:
230 self.mounts.append("/var/log/portage")
231 self.mountmap["/var/log/portage"]=self.settings["port_logdir"]
232 self.env["PORT_LOGDIR"]="/var/log/portage"
233 self.env["PORT_LOGDIR_CLEAN"]='find "${PORT_LOGDIR}" -type f ! -name "summary.log*" -mtime +30 -delete'
235 def override_cbuild(self):
236 if "CBUILD" in self.makeconf:
237 self.settings["CBUILD"]=self.makeconf["CBUILD"]
239 def override_chost(self):
240 if "CHOST" in self.makeconf:
241 self.settings["CHOST"]=self.makeconf["CHOST"]
243 def override_cflags(self):
244 if "CFLAGS" in self.makeconf:
245 self.settings["CFLAGS"]=self.makeconf["CFLAGS"]
247 def override_cxxflags(self):
248 if "CXXFLAGS" in self.makeconf:
249 self.settings["CXXFLAGS"]=self.makeconf["CXXFLAGS"]
251 def override_ldflags(self):
252 if "LDFLAGS" in self.makeconf:
253 self.settings["LDFLAGS"]=self.makeconf["LDFLAGS"]
255 def set_install_mask(self):
256 if "install_mask" in self.settings:
257 if type(self.settings["install_mask"])!=types.StringType:
258 self.settings["install_mask"]=\
259 string.join(self.settings["install_mask"])
261 def set_spec_prefix(self):
262 self.settings["spec_prefix"]=self.settings["target"]
264 def set_target_profile(self):
265 self.settings["target_profile"]=self.settings["profile"]
267 def set_target_subpath(self):
268 self.settings["target_subpath"]=self.settings["rel_type"]+"/"+\
269 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
270 self.settings["version_stamp"]
272 def set_source_subpath(self):
273 if type(self.settings["source_subpath"])!=types.StringType:
274 raise CatalystError,\
275 "source_subpath should have been a string. Perhaps you have something wrong in your spec file?"
277 def set_pkgcache_path(self):
278 if "pkgcache_path" in self.settings:
279 if type(self.settings["pkgcache_path"])!=types.StringType:
280 self.settings["pkgcache_path"]=\
281 normpath(string.join(self.settings["pkgcache_path"]))
283 self.settings["pkgcache_path"]=\
284 normpath(self.settings["storedir"]+"/packages/"+\
285 self.settings["target_subpath"]+"/")
287 def set_kerncache_path(self):
288 if "kerncache_path" in self.settings:
289 if type(self.settings["kerncache_path"])!=types.StringType:
290 self.settings["kerncache_path"]=\
291 normpath(string.join(self.settings["kerncache_path"]))
293 self.settings["kerncache_path"]=normpath(self.settings["storedir"]+\
294 "/kerncache/"+self.settings["target_subpath"]+"/")
296 def set_target_path(self):
297 self.settings["target_path"]=normpath(self.settings["storedir"]+\
298 "/builds/"+self.settings["target_subpath"]+".tar.bz2")
299 if "AUTORESUME" in self.settings\
300 and os.path.exists(self.settings["autoresume_path"]+\
301 "setup_target_path"):
303 "Resume point detected, skipping target path setup operation..."
305 """ First clean up any existing target stuff """
306 # XXX WTF are we removing the old tarball before we start building the
307 # XXX new one? If the build fails, you don't want to be left with
309 # if os.path.isfile(self.settings["target_path"]):
310 # cmd("rm -f "+self.settings["target_path"],\
311 # "Could not remove existing file: "\
312 # +self.settings["target_path"],env=self.env)
313 touch(self.settings["autoresume_path"]+"setup_target_path")
315 if not os.path.exists(self.settings["storedir"]+"/builds/"):
316 os.makedirs(self.settings["storedir"]+"/builds/")
318 def set_fsscript(self):
319 if self.settings["spec_prefix"]+"/fsscript" in self.settings:
320 self.settings["fsscript"]=\
321 self.settings[self.settings["spec_prefix"]+"/fsscript"]
322 del self.settings[self.settings["spec_prefix"]+"/fsscript"]
325 if self.settings["spec_prefix"]+"/rcadd" in self.settings:
326 self.settings["rcadd"]=\
327 self.settings[self.settings["spec_prefix"]+"/rcadd"]
328 del self.settings[self.settings["spec_prefix"]+"/rcadd"]
331 if self.settings["spec_prefix"]+"/rcdel" in self.settings:
332 self.settings["rcdel"]=\
333 self.settings[self.settings["spec_prefix"]+"/rcdel"]
334 del self.settings[self.settings["spec_prefix"]+"/rcdel"]
337 if self.settings["spec_prefix"]+"/cdtar" in self.settings:
338 self.settings["cdtar"]=\
339 normpath(self.settings[self.settings["spec_prefix"]+"/cdtar"])
340 del self.settings[self.settings["spec_prefix"]+"/cdtar"]
343 if self.settings["spec_prefix"]+"/iso" in self.settings:
344 if self.settings[self.settings["spec_prefix"]+"/iso"].startswith('/'):
345 self.settings["iso"]=\
346 normpath(self.settings[self.settings["spec_prefix"]+"/iso"])
348 # This automatically prepends the build dir to the ISO output path
349 # if it doesn't start with a /
350 self.settings["iso"] = normpath(self.settings["storedir"] + \
351 "/builds/" + self.settings["rel_type"] + "/" + \
352 self.settings[self.settings["spec_prefix"]+"/iso"])
353 del self.settings[self.settings["spec_prefix"]+"/iso"]
355 def set_fstype(self):
356 if self.settings["spec_prefix"]+"/fstype" in self.settings:
357 self.settings["fstype"]=\
358 self.settings[self.settings["spec_prefix"]+"/fstype"]
359 del self.settings[self.settings["spec_prefix"]+"/fstype"]
361 if "fstype" not in self.settings:
362 self.settings["fstype"]="normal"
363 for x in self.valid_values:
364 if x == self.settings["spec_prefix"]+"/fstype":
365 print "\n"+self.settings["spec_prefix"]+\
366 "/fstype is being set to the default of \"normal\"\n"
369 if "fstype" in self.settings:
370 self.valid_values.append("fsops")
371 if self.settings["spec_prefix"]+"/fsops" in self.settings:
372 self.settings["fsops"]=\
373 self.settings[self.settings["spec_prefix"]+"/fsops"]
374 del self.settings[self.settings["spec_prefix"]+"/fsops"]
376 def set_source_path(self):
377 if "SEEDCACHE" in self.settings\
378 and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+\
379 self.settings["source_subpath"]+"/")):
380 self.settings["source_path"]=normpath(self.settings["storedir"]+\
381 "/tmp/"+self.settings["source_subpath"]+"/")
383 self.settings["source_path"]=normpath(self.settings["storedir"]+\
384 "/builds/"+self.settings["source_subpath"]+".tar.bz2")
385 if os.path.isfile(self.settings["source_path"]):
386 # XXX: Is this even necessary if the previous check passes?
387 if os.path.exists(self.settings["source_path"]):
388 self.settings["source_path_hash"]=\
389 generate_hash(self.settings["source_path"],\
390 hash_function=self.settings["hash_function"],\
392 print "Source path set to "+self.settings["source_path"]
393 if os.path.isdir(self.settings["source_path"]):
394 print "\tIf this is not desired, remove this directory or turn off"
395 print "\tseedcache in the options of catalyst.conf the source path"
396 print "\twill then be "+\
397 normpath(self.settings["storedir"]+"/builds/"+\
398 self.settings["source_subpath"]+".tar.bz2\n")
400 def set_dest_path(self):
401 if "root_path" in self.settings:
402 self.settings["destpath"]=normpath(self.settings["chroot_path"]+\
403 self.settings["root_path"])
405 self.settings["destpath"]=normpath(self.settings["chroot_path"])
407 def set_cleanables(self):
408 self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/tmp/*",\
409 "/root/*","/usr/portage"]
411 def set_snapshot_path(self):
412 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
413 "/snapshots/portage-"+self.settings["snapshot"]+".tar.xz")
415 if os.path.exists(self.settings["snapshot_path"]):
416 self.settings["snapshot_path_hash"]=\
417 generate_hash(self.settings["snapshot_path"],\
418 hash_function=self.settings["hash_function"],verbose=False)
420 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
421 "/snapshots/portage-"+self.settings["snapshot"]+".tar.bz2")
423 if os.path.exists(self.settings["snapshot_path"]):
424 self.settings["snapshot_path_hash"]=\
425 generate_hash(self.settings["snapshot_path"],\
426 hash_function=self.settings["hash_function"],verbose=False)
428 def set_snapcache_path(self):
429 if "SNAPCACHE" in self.settings:
430 self.settings["snapshot_cache_path"]=\
431 normpath(self.settings["snapshot_cache"]+"/"+\
432 self.settings["snapshot"]+"/")
433 self.snapcache_lock=\
434 catalyst_lock.LockDir(self.settings["snapshot_cache_path"])
435 print "Caching snapshot to "+self.settings["snapshot_cache_path"]
437 def set_chroot_path(self):
439 NOTE: the trailing slash is very important!
440 Things *will* break without it!
442 self.settings["chroot_path"]=normpath(self.settings["storedir"]+\
443 "/tmp/"+self.settings["target_subpath"]+"/")
444 self.chroot_lock=catalyst_lock.LockDir(self.settings["chroot_path"])
446 def set_autoresume_path(self):
447 self.settings["autoresume_path"]=normpath(self.settings["storedir"]+\
448 "/tmp/"+self.settings["rel_type"]+"/"+".autoresume-"+\
449 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
450 self.settings["version_stamp"]+"/")
451 if "AUTORESUME" in self.settings:
452 print "The autoresume path is " + self.settings["autoresume_path"]
453 if not os.path.exists(self.settings["autoresume_path"]):
454 os.makedirs(self.settings["autoresume_path"],0755)
456 def set_controller_file(self):
457 self.settings["controller_file"]=normpath(self.settings["sharedir"]+\
458 "/targets/"+self.settings["target"]+"/"+self.settings["target"]+\
461 def set_iso_volume_id(self):
462 if self.settings["spec_prefix"]+"/volid" in self.settings:
463 self.settings["iso_volume_id"]=\
464 self.settings[self.settings["spec_prefix"]+"/volid"]
465 if len(self.settings["iso_volume_id"])>32:
466 raise CatalystError,\
467 "ISO volume ID must not exceed 32 characters."
469 self.settings["iso_volume_id"]="catalyst "+self.settings["snapshot"]
471 def set_action_sequence(self):
472 """ Default action sequence for run method """
473 self.settings["action_sequence"]=["unpack","unpack_snapshot",\
474 "setup_confdir","portage_overlay",\
475 "base_dirs","bind","chroot_setup","setup_environment",\
476 "run_local","preclean","unbind","clean"]
477 # if "TARBALL" in self.settings or \
478 # "FETCH" not in self.settings:
479 if "FETCH" not in self.settings:
480 self.settings["action_sequence"].append("capture")
481 self.settings["action_sequence"].append("clear_autoresume")
484 if self.settings["spec_prefix"]+"/use" in self.settings:
485 self.settings["use"]=\
486 self.settings[self.settings["spec_prefix"]+"/use"]
487 del self.settings[self.settings["spec_prefix"]+"/use"]
488 if "use" not in self.settings:
489 self.settings["use"]=""
490 if type(self.settings["use"])==types.StringType:
491 self.settings["use"]=self.settings["use"].split()
493 # Force bindist when options ask for it
494 if "BINDIST" in self.settings:
495 self.settings["use"].append("bindist")
497 def set_stage_path(self):
498 self.settings["stage_path"]=normpath(self.settings["chroot_path"])
500 def set_mounts(self):
503 def set_packages(self):
507 if self.settings["spec_prefix"]+"/rm" in self.settings:
508 if type(self.settings[self.settings["spec_prefix"]+\
509 "/rm"])==types.StringType:
510 self.settings[self.settings["spec_prefix"]+"/rm"]=\
511 self.settings[self.settings["spec_prefix"]+"/rm"].split()
513 def set_linuxrc(self):
514 if self.settings["spec_prefix"]+"/linuxrc" in self.settings:
515 if type(self.settings[self.settings["spec_prefix"]+\
516 "/linuxrc"])==types.StringType:
517 self.settings["linuxrc"]=\
518 self.settings[self.settings["spec_prefix"]+"/linuxrc"]
519 del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
521 def set_busybox_config(self):
522 if self.settings["spec_prefix"]+"/busybox_config" in self.settings:
523 if type(self.settings[self.settings["spec_prefix"]+\
524 "/busybox_config"])==types.StringType:
525 self.settings["busybox_config"]=\
526 self.settings[self.settings["spec_prefix"]+"/busybox_config"]
527 del self.settings[self.settings["spec_prefix"]+"/busybox_config"]
529 def set_portage_overlay(self):
530 if "portage_overlay" in self.settings:
531 if type(self.settings["portage_overlay"])==types.StringType:
532 self.settings["portage_overlay"]=\
533 self.settings["portage_overlay"].split()
534 print "portage_overlay directories are set to: \""+\
535 string.join(self.settings["portage_overlay"])+"\""
537 def set_overlay(self):
538 if self.settings["spec_prefix"]+"/overlay" in self.settings:
539 if type(self.settings[self.settings["spec_prefix"]+\
540 "/overlay"])==types.StringType:
541 self.settings[self.settings["spec_prefix"]+"/overlay"]=\
542 self.settings[self.settings["spec_prefix"]+\
545 def set_root_overlay(self):
546 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
547 if type(self.settings[self.settings["spec_prefix"]+\
548 "/root_overlay"])==types.StringType:
549 self.settings[self.settings["spec_prefix"]+"/root_overlay"]=\
550 self.settings[self.settings["spec_prefix"]+\
551 "/root_overlay"].split()
553 def set_root_path(self):
554 """ ROOT= variable for emerges """
555 self.settings["root_path"]="/"
557 def set_valid_build_kernel_vars(self,addlargs):
558 if "boot/kernel" in addlargs:
559 if type(addlargs["boot/kernel"])==types.StringType:
560 loopy=[addlargs["boot/kernel"]]
562 loopy=addlargs["boot/kernel"]
565 self.valid_values.append("boot/kernel/"+x+"/aliases")
566 self.valid_values.append("boot/kernel/"+x+"/config")
567 self.valid_values.append("boot/kernel/"+x+"/console")
568 self.valid_values.append("boot/kernel/"+x+"/extraversion")
569 self.valid_values.append("boot/kernel/"+x+"/gk_action")
570 self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
571 self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
572 self.valid_values.append("boot/kernel/"+x+"/machine_type")
573 self.valid_values.append("boot/kernel/"+x+"/sources")
574 self.valid_values.append("boot/kernel/"+x+"/softlevel")
575 self.valid_values.append("boot/kernel/"+x+"/use")
576 self.valid_values.append("boot/kernel/"+x+"/packages")
577 if "boot/kernel/"+x+"/packages" in addlargs:
578 if type(addlargs["boot/kernel/"+x+\
579 "/packages"])==types.StringType:
580 addlargs["boot/kernel/"+x+"/packages"]=\
581 [addlargs["boot/kernel/"+x+"/packages"]]
583 def set_build_kernel_vars(self):
584 if self.settings["spec_prefix"]+"/gk_mainargs" in self.settings:
585 self.settings["gk_mainargs"]=\
586 self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
587 del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
589 def kill_chroot_pids(self):
590 print "Checking for processes running in chroot and killing them."
593 Force environment variables to be exported so script can see them
595 self.setup_environment()
597 if os.path.exists(self.settings["sharedir"]+\
598 "/targets/support/kill-chroot-pids.sh"):
599 cmd("/bin/bash "+self.settings["sharedir"]+\
600 "/targets/support/kill-chroot-pids.sh",\
601 "kill-chroot-pids script failed.",env=self.env)
603 def mount_safety_check(self):
604 mypath=self.settings["chroot_path"]
607 Check and verify that none of our paths in mypath are mounted. We don't
608 want to clean up with things still mounted, and this allows us to check.
609 Returns 1 on ok, 0 on "something is still mounted" case.
612 if not os.path.exists(mypath):
615 for x in self.mounts:
616 if not os.path.exists(mypath+x):
619 if ismount(mypath+x):
620 """ Something is still mounted "" """
622 print x+" is still mounted; performing auto-bind-umount...",
623 """ Try to umount stuff ourselves """
625 if ismount(mypath+x):
626 raise CatalystError, "Auto-unbind failed for "+x
628 print "Auto-unbind successful..."
629 except CatalystError:
630 raise CatalystError, "Unable to auto-unbind "+x
635 clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+\
638 if "SEEDCACHE" in self.settings:
639 if os.path.isdir(self.settings["source_path"]):
640 """ SEEDCACHE Is a directory, use rsync """
641 unpack_cmd="rsync -a --delete "+self.settings["source_path"]+\
642 " "+self.settings["chroot_path"]
643 display_msg="\nStarting rsync from "+\
644 self.settings["source_path"]+"\nto "+\
645 self.settings["chroot_path"]+\
646 " (This may take some time) ...\n"
647 error_msg="Rsync of "+self.settings["source_path"]+" to "+\
648 self.settings["chroot_path"]+" failed."
650 """ SEEDCACHE is a not a directory, try untar'ing """
651 print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
652 display_msg="\nStarting tar extract from "+\
653 self.settings["source_path"]+"\nto "+\
654 self.settings["chroot_path"]+\
655 " (This may take some time) ...\n"
656 if "bz2" == self.settings["chroot_path"][-3:]:
657 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
658 self.settings["chroot_path"]
660 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
661 self.settings["chroot_path"]
662 error_msg="Tarball extraction of "+\
663 self.settings["source_path"]+" to "+\
664 self.settings["chroot_path"]+" failed."
666 """ No SEEDCACHE, use tar """
667 display_msg="\nStarting tar extract from "+\
668 self.settings["source_path"]+"\nto "+\
669 self.settings["chroot_path"]+\
670 " (This may take some time) ...\n"
671 if "bz2" == self.settings["chroot_path"][-3:]:
672 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
673 self.settings["chroot_path"]
675 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
676 self.settings["chroot_path"]
677 error_msg="Tarball extraction of "+self.settings["source_path"]+\
678 " to "+self.settings["chroot_path"]+" failed."
680 if "AUTORESUME" in self.settings:
681 if os.path.isdir(self.settings["source_path"]) \
682 and os.path.exists(self.settings["autoresume_path"]+"unpack"):
683 """ Autoresume is valid, SEEDCACHE is valid """
685 invalid_snapshot=False
687 elif os.path.isfile(self.settings["source_path"]) \
688 and self.settings["source_path_hash"]==clst_unpack_hash:
689 """ Autoresume is valid, tarball is valid """
691 invalid_snapshot=True
693 elif os.path.isdir(self.settings["source_path"]) \
694 and not os.path.exists(self.settings["autoresume_path"]+\
696 """ Autoresume is invalid, SEEDCACHE """
698 invalid_snapshot=False
700 elif os.path.isfile(self.settings["source_path"]) \
701 and self.settings["source_path_hash"]!=clst_unpack_hash:
702 """ Autoresume is invalid, tarball """
704 invalid_snapshot=True
706 """ No autoresume, SEEDCACHE """
707 if "SEEDCACHE" in self.settings:
708 """ SEEDCACHE so let's run rsync and let it clean up """
709 if os.path.isdir(self.settings["source_path"]):
711 invalid_snapshot=False
712 elif os.path.isfile(self.settings["source_path"]):
713 """ Tarball so unpack and remove anything already there """
715 invalid_snapshot=True
716 """ No autoresume, no SEEDCACHE """
718 """ Tarball so unpack and remove anything already there """
719 if os.path.isfile(self.settings["source_path"]):
721 invalid_snapshot=True
722 elif os.path.isdir(self.settings["source_path"]):
723 """ We should never reach this, so something is very wrong """
724 raise CatalystError,\
725 "source path is a dir but seedcache is not enabled"
728 self.mount_safety_check()
731 if "AUTORESUME" in self.settings:
732 print "No Valid Resume point detected, cleaning up..."
734 self.clear_autoresume()
737 if not os.path.exists(self.settings["chroot_path"]):
738 os.makedirs(self.settings["chroot_path"])
740 if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
741 os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
743 if "PKGCACHE" in self.settings:
744 if not os.path.exists(self.settings["pkgcache_path"]):
745 os.makedirs(self.settings["pkgcache_path"],0755)
747 if "KERNCACHE" in self.settings:
748 if not os.path.exists(self.settings["kerncache_path"]):
749 os.makedirs(self.settings["kerncache_path"],0755)
752 cmd(unpack_cmd,error_msg,env=self.env)
754 if "source_path_hash" in self.settings:
755 myf=open(self.settings["autoresume_path"]+"unpack","w")
756 myf.write(self.settings["source_path_hash"])
759 touch(self.settings["autoresume_path"]+"unpack")
761 print "Resume point detected, skipping unpack operation..."
763 def unpack_snapshot(self):
765 snapshot_hash=read_from_clst(self.settings["autoresume_path"]+\
768 if "SNAPCACHE" in self.settings:
769 snapshot_cache_hash=\
770 read_from_clst(self.settings["snapshot_cache_path"]+\
772 destdir=self.settings["snapshot_cache_path"]
773 if "bz2" == self.settings["chroot_path"][-3:]:
774 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+destdir
776 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+destdir
777 unpack_errmsg="Error unpacking snapshot"
778 cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+\
779 self.settings["snapshot_cache_path"]+\
780 " (This can take a long time)..."
781 cleanup_errmsg="Error removing existing snapshot cache directory."
782 self.snapshot_lock_object=self.snapcache_lock
784 if self.settings["snapshot_path_hash"]==snapshot_cache_hash:
785 print "Valid snapshot cache, skipping unpack of portage tree..."
788 destdir=normpath(self.settings["chroot_path"]+"/usr/portage")
789 cleanup_errmsg="Error removing existing snapshot directory."
791 "Cleaning up existing portage tree (This can take a long time)..."
792 if "bz2" == self.settings["chroot_path"][-3:]:
793 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+\
794 self.settings["chroot_path"]+"/usr"
796 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+\
797 self.settings["chroot_path"]+"/usr"
798 unpack_errmsg="Error unpacking snapshot"
800 if "AUTORESUME" in self.settings \
801 and os.path.exists(self.settings["chroot_path"]+\
803 and os.path.exists(self.settings["autoresume_path"]\
805 and self.settings["snapshot_path_hash"] == snapshot_hash:
807 "Valid Resume point detected, skipping unpack of portage tree..."
811 if "SNAPCACHE" in self.settings:
812 self.snapshot_lock_object.write_lock()
813 if os.path.exists(destdir):
815 cleanup_cmd="rm -rf "+destdir
816 cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
817 if not os.path.exists(destdir):
818 os.makedirs(destdir,0755)
820 print "Unpacking portage tree (This can take a long time) ..."
821 cmd(unpack_cmd,unpack_errmsg,env=self.env)
823 if "SNAPCACHE" in self.settings:
824 myf=open(self.settings["snapshot_cache_path"]+"catalyst-hash","w")
825 myf.write(self.settings["snapshot_path_hash"])
828 print "Setting snapshot autoresume point"
829 myf=open(self.settings["autoresume_path"]+"unpack_portage","w")
830 myf.write(self.settings["snapshot_path_hash"])
833 if "SNAPCACHE" in self.settings:
834 self.snapshot_lock_object.unlock()
836 def config_profile_link(self):
837 if "AUTORESUME" in self.settings \
838 and os.path.exists(self.settings["autoresume_path"]+\
839 "config_profile_link"):
841 "Resume point detected, skipping config_profile_link operation..."
843 # TODO: zmedico and I discussed making this a directory and pushing
844 # in a parent file, as well as other user-specified configuration.
845 print "Configuring profile link..."
846 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.profile",\
847 "Error zapping profile link",env=self.env)
848 cmd("mkdir -p "+self.settings["chroot_path"]+"/etc/portage/")
849 cmd("ln -sf ../../usr/portage/profiles/"+\
850 self.settings["target_profile"]+" "+\
851 self.settings["chroot_path"]+"/etc/portage/make.profile",\
852 "Error creating profile link",env=self.env)
853 touch(self.settings["autoresume_path"]+"config_profile_link")
855 def setup_confdir(self):
856 if "AUTORESUME" in self.settings \
857 and os.path.exists(self.settings["autoresume_path"]+\
859 print "Resume point detected, skipping setup_confdir operation..."
861 if "portage_confdir" in self.settings:
862 print "Configuring /etc/portage..."
863 cmd("rsync -a "+self.settings["portage_confdir"]+"/ "+\
864 self.settings["chroot_path"]+"/etc/portage/",\
865 "Error copying /etc/portage",env=self.env)
866 touch(self.settings["autoresume_path"]+"setup_confdir")
868 def portage_overlay(self):
869 """ We copy the contents of our overlays to /usr/local/portage """
870 if "portage_overlay" in self.settings:
871 for x in self.settings["portage_overlay"]:
872 if os.path.exists(x):
873 print "Copying overlay dir " +x
874 cmd("mkdir -p "+self.settings["chroot_path"]+\
875 "/usr/local/portage",\
876 "Could not make portage_overlay dir",env=self.env)
877 cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+\
878 "/usr/local/portage",\
879 "Could not copy portage_overlay",env=self.env)
881 def root_overlay(self):
882 """ Copy over the root_overlay """
883 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
884 for x in self.settings[self.settings["spec_prefix"]+\
886 if os.path.exists(x):
887 print "Copying root_overlay: "+x
888 cmd("rsync -a "+x+"/ "+\
889 self.settings["chroot_path"],\
890 self.settings["spec_prefix"]+"/root_overlay: "+x+\
891 " copy failed.",env=self.env)
897 for x in self.mounts:
898 if not os.path.exists(self.settings["chroot_path"]+x):
899 os.makedirs(self.settings["chroot_path"]+x,0755)
901 if not os.path.exists(self.mountmap[x]):
902 if not self.mountmap[x] == "tmpfs":
903 os.makedirs(self.mountmap[x],0755)
906 if "SNAPCACHE" in self.settings and x == "/usr/portage":
907 self.snapshot_lock_object.read_lock()
908 if os.uname()[0] == "FreeBSD":
910 retval=os.system("mount -t devfs none "+\
911 self.settings["chroot_path"]+x)
913 retval=os.system("mount_nullfs "+src+" "+\
914 self.settings["chroot_path"]+x)
917 if "var_tmpfs_portage" in self.settings:
918 retval=os.system("mount -t tmpfs -o size="+\
919 self.settings["var_tmpfs_portage"]+"G "+src+" "+\
920 self.settings["chroot_path"]+x)
922 retval=os.system("mount --bind "+src+" "+\
923 self.settings["chroot_path"]+x)
926 raise CatalystError,"Couldn't bind mount "+src
930 mypath=self.settings["chroot_path"]
931 myrevmounts=self.mounts[:]
932 myrevmounts.reverse()
933 """ Unmount in reverse order for nested bind-mounts """
934 for x in myrevmounts:
935 if not os.path.exists(mypath+x):
938 if not ismount(mypath+x):
941 retval=os.system("umount "+\
942 os.path.join(mypath,x.lstrip(os.path.sep)))
945 warn("First attempt to unmount: "+mypath+x+" failed.")
946 warn("Killing any pids still running in the chroot")
948 self.kill_chroot_pids()
950 retval2=os.system("umount "+mypath+x)
953 warn("Couldn't umount bind mount: "+mypath+x)
955 if "SNAPCACHE" in self.settings and x == "/usr/portage":
958 It's possible the snapshot lock object isn't created yet.
959 This is because mount safety check calls unbind before the
960 target is fully initialized
962 self.snapshot_lock_object.unlock()
967 if any bind mounts really failed, then we need to raise
968 this to potentially prevent an upcoming bash stage cleanup script
969 from wiping our bind mounts.
971 raise CatalystError,\
972 "Couldn't umount one or more bind-mounts; aborting for safety."
974 def chroot_setup(self):
975 self.makeconf=read_makeconf(self.settings["chroot_path"]+\
976 "/etc/portage/make.conf")
977 self.override_cbuild()
978 self.override_chost()
979 self.override_cflags()
980 self.override_cxxflags()
981 self.override_ldflags()
982 if "AUTORESUME" in self.settings \
983 and os.path.exists(self.settings["autoresume_path"]+"chroot_setup"):
984 print "Resume point detected, skipping chroot_setup operation..."
986 print "Setting up chroot..."
988 #self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/portage/make.conf")
990 cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
991 "Could not copy resolv.conf into place.",env=self.env)
993 """ Copy over the envscript, if applicable """
994 if "ENVSCRIPT" in self.settings:
995 if not os.path.exists(self.settings["ENVSCRIPT"]):
996 raise CatalystError,\
997 "Can't find envscript "+self.settings["ENVSCRIPT"]
999 print "\nWarning!!!!"
1000 print "\tOverriding certain env variables may cause catastrophic failure."
1001 print "\tIf your build fails look here first as the possible problem."
1002 print "\tCatalyst assumes you know what you are doing when setting"
1003 print "\t\tthese variables."
1004 print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
1005 print "\tYou have been warned\n"
1007 cmd("cp "+self.settings["ENVSCRIPT"]+" "+\
1008 self.settings["chroot_path"]+"/tmp/envscript",\
1009 "Could not copy envscript into place.",env=self.env)
1012 Copy over /etc/hosts from the host in case there are any
1013 specialties in there
1015 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
1016 cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+\
1017 self.settings["chroot_path"]+"/etc/hosts.catalyst",\
1018 "Could not backup /etc/hosts",env=self.env)
1019 cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts",\
1020 "Could not copy /etc/hosts",env=self.env)
1022 """ Modify and write out make.conf (for the chroot) """
1023 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.conf",\
1024 "Could not remove "+self.settings["chroot_path"]+\
1025 "/etc/portage/make.conf",env=self.env)
1026 myf=open(self.settings["chroot_path"]+"/etc/portage/make.conf","w")
1027 myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
1028 myf.write("# Please consult /usr/share/portage/config/make.conf.example for a more\n# detailed example.\n")
1029 if "CFLAGS" in self.settings:
1030 myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
1031 if "CXXFLAGS" in self.settings:
1032 if self.settings["CXXFLAGS"]!=self.settings["CFLAGS"]:
1033 myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
1035 myf.write('CXXFLAGS="${CFLAGS}"\n')
1037 myf.write('CXXFLAGS="${CFLAGS}"\n')
1039 if "LDFLAGS" in self.settings:
1040 myf.write("# LDFLAGS is unsupported. USE AT YOUR OWN RISK!\n")
1041 myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
1042 if "CBUILD" in self.settings:
1043 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")
1044 myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
1046 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")
1047 myf.write('CHOST="'+self.settings["CHOST"]+'"\n')
1049 """ Figure out what our USE vars are for building """
1051 if "HOSTUSE" in self.settings:
1052 myusevars.extend(self.settings["HOSTUSE"])
1054 if "use" in self.settings:
1055 myusevars.extend(self.settings["use"])
1058 myf.write("# These are the USE flags that were used in addition to what is provided by the\n# profile used for building.\n")
1059 myusevars = sorted(set(myusevars))
1060 myf.write('USE="'+string.join(myusevars)+'"\n')
1061 if '-*' in myusevars:
1062 print "\nWarning!!! "
1063 print "\tThe use of -* in "+self.settings["spec_prefix"]+\
1064 "/use will cause portage to ignore"
1065 print "\tpackage.use in the profile and portage_confdir. You've been warned!"
1067 myf.write('PORTDIR="/usr/portage"\n')
1068 myf.write('DISTDIR="${PORTDIR}/distfiles"\n')
1069 myf.write('PKGDIR="${PORTDIR}/packages"\n')
1071 """ Setup the portage overlay """
1072 if "portage_overlay" in self.settings:
1073 myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
1076 cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
1077 self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
1078 "Could not backup /etc/portage/make.conf",env=self.env)
1079 touch(self.settings["autoresume_path"]+"chroot_setup")
1082 if "AUTORESUME" in self.settings \
1083 and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
1084 print "Resume point detected, skipping fsscript operation..."
1086 if "fsscript" in self.settings:
1087 if os.path.exists(self.settings["controller_file"]):
1088 cmd("/bin/bash "+self.settings["controller_file"]+\
1089 " fsscript","fsscript script failed.",env=self.env)
1090 touch(self.settings["autoresume_path"]+"fsscript")
1093 if "AUTORESUME" in self.settings \
1094 and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
1095 print "Resume point detected, skipping rcupdate operation..."
1097 if os.path.exists(self.settings["controller_file"]):
1098 cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
1099 "rc-update script failed.",env=self.env)
1100 touch(self.settings["autoresume_path"]+"rcupdate")
1103 if "AUTORESUME" in self.settings \
1104 and os.path.exists(self.settings["autoresume_path"]+"clean"):
1105 print "Resume point detected, skipping clean operation..."
1107 for x in self.settings["cleanables"]:
1108 print "Cleaning chroot: "+x+"... "
1109 cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
1112 """ Put /etc/hosts back into place """
1113 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
1114 cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
1115 self.settings["chroot_path"]+"/etc/hosts",\
1116 "Could not replace /etc/hosts",env=self.env)
1118 """ Remove our overlay """
1119 if os.path.exists(self.settings["chroot_path"]+"/usr/local/portage"):
1120 cmd("rm -rf "+self.settings["chroot_path"]+"/usr/local/portage",\
1121 "Could not remove /usr/local/portage",env=self.env)
1122 cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
1123 "/etc/portage/make.conf",\
1124 "Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
1126 """ Clean up old and obsoleted files in /etc """
1127 if os.path.exists(self.settings["stage_path"]+"/etc"):
1128 cmd("find "+self.settings["stage_path"]+\
1129 "/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
1130 "Could not remove stray files in /etc",env=self.env)
1132 if os.path.exists(self.settings["controller_file"]):
1133 cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
1134 "clean script failed.",env=self.env)
1135 touch(self.settings["autoresume_path"]+"clean")
1138 if "AUTORESUME" in self.settings \
1139 and os.path.exists(self.settings["autoresume_path"]+"empty"):
1140 print "Resume point detected, skipping empty operation..."
1142 if self.settings["spec_prefix"]+"/empty" in self.settings:
1143 if type(self.settings[self.settings["spec_prefix"]+\
1144 "/empty"])==types.StringType:
1145 self.settings[self.settings["spec_prefix"]+"/empty"]=\
1146 self.settings[self.settings["spec_prefix"]+\
1148 for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
1149 myemp=self.settings["destpath"]+x
1150 if not os.path.isdir(myemp) or os.path.islink(myemp):
1151 print x,"not a directory or does not exist, skipping 'empty' operation."
1153 print "Emptying directory",x
1155 stat the dir, delete the dir, recreate the dir and set
1156 the proper perms and ownership
1158 mystat=os.stat(myemp)
1159 shutil.rmtree(myemp)
1160 os.makedirs(myemp,0755)
1161 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1162 os.chmod(myemp,mystat[ST_MODE])
1163 touch(self.settings["autoresume_path"]+"empty")
1166 if "AUTORESUME" in self.settings \
1167 and os.path.exists(self.settings["autoresume_path"]+"remove"):
1168 print "Resume point detected, skipping remove operation..."
1170 if self.settings["spec_prefix"]+"/rm" in self.settings:
1171 for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
1173 We're going to shell out for all these cleaning
1174 operations, so we get easy glob handling.
1176 print "livecd: removing "+x
1177 os.system("rm -rf "+self.settings["chroot_path"]+x)
1179 if os.path.exists(self.settings["controller_file"]):
1180 cmd("/bin/bash "+self.settings["controller_file"]+\
1181 " clean","Clean failed.",env=self.env)
1182 touch(self.settings["autoresume_path"]+"remove")
1188 if "AUTORESUME" in self.settings \
1189 and os.path.exists(self.settings["autoresume_path"]+"preclean"):
1190 print "Resume point detected, skipping preclean operation..."
1193 if os.path.exists(self.settings["controller_file"]):
1194 cmd("/bin/bash "+self.settings["controller_file"]+\
1195 " preclean","preclean script failed.",env=self.env)
1196 touch(self.settings["autoresume_path"]+"preclean")
1200 raise CatalystError, "Build failed, could not execute preclean"
1203 if "AUTORESUME" in self.settings \
1204 and os.path.exists(self.settings["autoresume_path"]+"capture"):
1205 print "Resume point detected, skipping capture operation..."
1207 """ Capture target in a tarball """
1208 mypath=self.settings["target_path"].split("/")
1209 """ Remove filename from path """
1210 mypath=string.join(mypath[:-1],"/")
1212 """ Now make sure path exists """
1213 if not os.path.exists(mypath):
1216 print "Creating stage tarball..."
1218 cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
1219 self.settings["stage_path"]+" .",\
1220 "Couldn't create stage tarball",env=self.env)
1222 self.gen_contents_file(self.settings["target_path"])
1223 self.gen_digest_file(self.settings["target_path"])
1225 touch(self.settings["autoresume_path"]+"capture")
1227 def run_local(self):
1228 if "AUTORESUME" in self.settings \
1229 and os.path.exists(self.settings["autoresume_path"]+"run_local"):
1230 print "Resume point detected, skipping run_local operation..."
1233 if os.path.exists(self.settings["controller_file"]):
1234 cmd("/bin/bash "+self.settings["controller_file"]+" run",\
1235 "run script failed.",env=self.env)
1236 touch(self.settings["autoresume_path"]+"run_local")
1238 except CatalystError:
1240 raise CatalystError,"Stage build aborting due to error."
1242 def setup_environment(self):
1244 Modify the current environment. This is an ugly hack that should be
1245 fixed. We need this to use the os.system() call since we can't
1246 specify our own environ
1248 for x in self.settings.keys():
1249 """ Sanitize var names by doing "s|/-.|_|g" """
1250 varname="clst_"+string.replace(x,"/","_")
1251 varname=string.replace(varname,"-","_")
1252 varname=string.replace(varname,".","_")
1253 if type(self.settings[x])==types.StringType:
1254 """ Prefix to prevent namespace clashes """
1255 #os.environ[varname]=self.settings[x]
1256 self.env[varname]=self.settings[x]
1257 elif type(self.settings[x])==types.ListType:
1258 #os.environ[varname]=string.join(self.settings[x])
1259 self.env[varname]=string.join(self.settings[x])
1260 elif type(self.settings[x])==types.BooleanType:
1261 if self.settings[x]:
1262 self.env[varname]="true"
1264 self.env[varname]="false"
1265 if "makeopts" in self.settings:
1266 self.env["MAKEOPTS"]=self.settings["makeopts"]
1269 self.chroot_lock.write_lock()
1271 """ Kill any pids in the chroot "" """
1272 self.kill_chroot_pids()
1274 """ Check for mounts right away and abort if we cannot unmount them """
1275 self.mount_safety_check()
1277 if "CLEAR_AUTORESUME" in self.settings:
1278 self.clear_autoresume()
1280 if "PURGETMPONLY" in self.settings:
1284 if "PURGEONLY" in self.settings:
1288 if "PURGE" in self.settings:
1291 for x in self.settings["action_sequence"]:
1292 print "--- Running action sequence: "+x
1295 apply(getattr(self,x))
1297 self.mount_safety_check()
1300 self.chroot_lock.unlock()
1303 if "AUTORESUME" in self.settings \
1304 and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
1305 print "Resume point detected, skipping unmerge operation..."
1307 if self.settings["spec_prefix"]+"/unmerge" in self.settings:
1308 if type(self.settings[self.settings["spec_prefix"]+\
1309 "/unmerge"])==types.StringType:
1310 self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
1311 [self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1313 self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1315 for x in range(0,len(myunmerge)):
1317 Surround args with quotes for passing to bash, allows
1318 things like "<" to remain intact
1320 myunmerge[x]="'"+myunmerge[x]+"'"
1321 myunmerge=string.join(myunmerge)
1323 """ Before cleaning, unmerge stuff """
1325 cmd("/bin/bash "+self.settings["controller_file"]+\
1326 " unmerge "+ myunmerge,"Unmerge script failed.",\
1328 print "unmerge shell script"
1329 except CatalystError:
1332 touch(self.settings["autoresume_path"]+"unmerge")
1334 def target_setup(self):
1335 if "AUTORESUME" in self.settings \
1336 and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
1337 print "Resume point detected, skipping target_setup operation..."
1339 print "Setting up filesystems per filesystem type"
1340 cmd("/bin/bash "+self.settings["controller_file"]+\
1341 " target_image_setup "+ self.settings["target_path"],\
1342 "target_image_setup script failed.",env=self.env)
1343 touch(self.settings["autoresume_path"]+"target_setup")
1345 def setup_overlay(self):
1346 if "AUTORESUME" in self.settings \
1347 and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
1348 print "Resume point detected, skipping setup_overlay operation..."
1350 if self.settings["spec_prefix"]+"/overlay" in self.settings:
1351 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
1352 if os.path.exists(x):
1353 cmd("rsync -a "+x+"/ "+\
1354 self.settings["target_path"],\
1355 self.settings["spec_prefix"]+"overlay: "+x+\
1356 " copy failed.",env=self.env)
1357 touch(self.settings["autoresume_path"]+"setup_overlay")
1359 def create_iso(self):
1360 if "AUTORESUME" in self.settings \
1361 and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
1362 print "Resume point detected, skipping create_iso operation..."
1364 """ Create the ISO """
1365 if "iso" in self.settings:
1366 cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1367 self.settings["iso"],"ISO creation script failed.",\
1369 self.gen_contents_file(self.settings["iso"])
1370 self.gen_digest_file(self.settings["iso"])
1371 touch(self.settings["autoresume_path"]+"create_iso")
1373 print "WARNING: livecd/iso was not defined."
1374 print "An ISO Image will not be created."
1376 def build_packages(self):
1377 if "AUTORESUME" in self.settings \
1378 and os.path.exists(self.settings["autoresume_path"]+\
1380 print "Resume point detected, skipping build_packages operation..."
1382 if self.settings["spec_prefix"]+"/packages" in self.settings:
1383 if "AUTORESUME" in self.settings \
1384 and os.path.exists(self.settings["autoresume_path"]+\
1386 print "Resume point detected, skipping build_packages operation..."
1389 list_bashify(self.settings[self.settings["spec_prefix"]\
1392 cmd("/bin/bash "+self.settings["controller_file"]+\
1393 " build_packages "+mypack,\
1394 "Error in attempt to build packages",env=self.env)
1395 touch(self.settings["autoresume_path"]+"build_packages")
1396 except CatalystError:
1398 raise CatalystError,self.settings["spec_prefix"]+\
1399 "build aborting due to error."
1401 def build_kernel(self):
1402 "Build all configured kernels"
1403 if "AUTORESUME" in self.settings \
1404 and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
1405 print "Resume point detected, skipping build_kernel operation..."
1407 if "boot/kernel" in self.settings:
1409 mynames=self.settings["boot/kernel"]
1410 if type(mynames)==types.StringType:
1413 Execute the script that sets up the kernel build environment
1415 cmd("/bin/bash "+self.settings["controller_file"]+\
1416 " pre-kmerge ","Runscript pre-kmerge failed",\
1418 for kname in mynames:
1419 self._build_kernel(kname=kname)
1420 touch(self.settings["autoresume_path"]+"build_kernel")
1421 except CatalystError:
1423 raise CatalystError,\
1424 "build aborting due to kernel build error."
1426 def _build_kernel(self, kname):
1427 "Build a single configured kernel by name"
1428 if "AUTORESUME" in self.settings \
1429 and os.path.exists(self.settings["autoresume_path"]\
1430 +"build_kernel_"+kname):
1431 print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1433 self._copy_kernel_config(kname=kname)
1436 If we need to pass special options to the bootloader
1437 for this kernel put them into the environment
1439 if "boot/kernel/"+kname+"/kernelopts" in self.settings:
1440 myopts=self.settings["boot/kernel/"+kname+\
1443 if type(myopts) != types.StringType:
1444 myopts = string.join(myopts)
1445 self.env[kname+"_kernelopts"]=myopts
1448 self.env[kname+"_kernelopts"]=""
1450 if "boot/kernel/"+kname+"/extraversion" not in self.settings:
1451 self.settings["boot/kernel/"+kname+\
1454 self.env["clst_kextraversion"]=\
1455 self.settings["boot/kernel/"+kname+\
1458 self._copy_initramfs_overlay(kname=kname)
1460 """ Execute the script that builds the kernel """
1461 cmd("/bin/bash "+self.settings["controller_file"]+\
1463 "Runscript kernel build failed",env=self.env)
1465 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1466 if os.path.exists(self.settings["chroot_path"]+\
1467 "/tmp/initramfs_overlay/"):
1468 print "Cleaning up temporary overlay dir"
1469 cmd("rm -R "+self.settings["chroot_path"]+\
1470 "/tmp/initramfs_overlay/",env=self.env)
1472 touch(self.settings["autoresume_path"]+\
1473 "build_kernel_"+kname)
1476 Execute the script that cleans up the kernel build
1479 cmd("/bin/bash "+self.settings["controller_file"]+\
1481 "Runscript post-kmerge failed",env=self.env)
1483 def _copy_kernel_config(self, kname):
1484 if "boot/kernel/"+kname+"/config" in self.settings:
1485 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1487 raise CatalystError,\
1488 "Can't find kernel config: "+\
1489 self.settings["boot/kernel/"+kname+\
1493 cmd("cp "+self.settings["boot/kernel/"+kname+\
1495 self.settings["chroot_path"]+"/var/tmp/"+\
1497 "Couldn't copy kernel config: "+\
1498 self.settings["boot/kernel/"+kname+\
1499 "/config"],env=self.env)
1501 except CatalystError:
1504 def _copy_initramfs_overlay(self, kname):
1505 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1506 if os.path.exists(self.settings["boot/kernel/"+\
1507 kname+"/initramfs_overlay"]):
1508 print "Copying initramfs_overlay dir "+\
1509 self.settings["boot/kernel/"+kname+\
1510 "/initramfs_overlay"]
1513 self.settings["chroot_path"]+\
1514 "/tmp/initramfs_overlay/"+\
1515 self.settings["boot/kernel/"+kname+\
1516 "/initramfs_overlay"],env=self.env)
1518 cmd("cp -R "+self.settings["boot/kernel/"+\
1519 kname+"/initramfs_overlay"]+"/* "+\
1520 self.settings["chroot_path"]+\
1521 "/tmp/initramfs_overlay/"+\
1522 self.settings["boot/kernel/"+kname+\
1523 "/initramfs_overlay"],env=self.env)
1525 def bootloader(self):
1526 if "AUTORESUME" in self.settings \
1527 and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
1528 print "Resume point detected, skipping bootloader operation..."
1531 cmd("/bin/bash "+self.settings["controller_file"]+\
1532 " bootloader " + self.settings["target_path"],\
1533 "Bootloader script failed.",env=self.env)
1534 touch(self.settings["autoresume_path"]+"bootloader")
1535 except CatalystError:
1537 raise CatalystError,"Script aborting due to error."
1539 def livecd_update(self):
1540 if "AUTORESUME" in self.settings \
1541 and os.path.exists(self.settings["autoresume_path"]+\
1543 print "Resume point detected, skipping build_packages operation..."
1546 cmd("/bin/bash "+self.settings["controller_file"]+\
1547 " livecd-update","livecd-update failed.",env=self.env)
1548 touch(self.settings["autoresume_path"]+"livecd_update")
1550 except CatalystError:
1552 raise CatalystError,"build aborting due to livecd_update error."
1554 def clear_chroot(self):
1555 myemp=self.settings["chroot_path"]
1556 if os.path.isdir(myemp):
1557 print "Emptying directory",myemp
1559 stat the dir, delete the dir, recreate the dir and set
1560 the proper perms and ownership
1562 mystat=os.stat(myemp)
1563 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1564 """ There's no easy way to change flags recursively in python """
1565 if os.uname()[0] == "FreeBSD":
1566 os.system("chflags -R noschg "+myemp)
1567 shutil.rmtree(myemp)
1568 os.makedirs(myemp,0755)
1569 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1570 os.chmod(myemp,mystat[ST_MODE])
1572 def clear_packages(self):
1573 if "PKGCACHE" in self.settings:
1574 print "purging the pkgcache ..."
1576 myemp=self.settings["pkgcache_path"]
1577 if os.path.isdir(myemp):
1578 print "Emptying directory",myemp
1580 stat the dir, delete the dir, recreate the dir and set
1581 the proper perms and ownership
1583 mystat=os.stat(myemp)
1584 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1585 shutil.rmtree(myemp)
1586 os.makedirs(myemp,0755)
1587 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1588 os.chmod(myemp,mystat[ST_MODE])
1590 def clear_kerncache(self):
1591 if "KERNCACHE" in self.settings:
1592 print "purging the kerncache ..."
1594 myemp=self.settings["kerncache_path"]
1595 if os.path.isdir(myemp):
1596 print "Emptying directory",myemp
1598 stat the dir, delete the dir, recreate the dir and set
1599 the proper perms and ownership
1601 mystat=os.stat(myemp)
1602 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1603 shutil.rmtree(myemp)
1604 os.makedirs(myemp,0755)
1605 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1606 os.chmod(myemp,mystat[ST_MODE])
1608 def clear_autoresume(self):
1609 """ Clean resume points since they are no longer needed """
1610 if "AUTORESUME" in self.settings:
1611 print "Removing AutoResume Points: ..."
1612 myemp=self.settings["autoresume_path"]
1613 if os.path.isdir(myemp):
1614 if "AUTORESUME" in self.settings:
1615 print "Emptying directory",myemp
1617 stat the dir, delete the dir, recreate the dir and set
1618 the proper perms and ownership
1620 mystat=os.stat(myemp)
1621 if os.uname()[0] == "FreeBSD":
1622 cmd("chflags -R noschg "+myemp,\
1623 "Could not remove immutable flag for file "\
1625 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1626 shutil.rmtree(myemp)
1627 os.makedirs(myemp,0755)
1628 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1629 os.chmod(myemp,mystat[ST_MODE])
1631 def gen_contents_file(self,file):
1632 if os.path.exists(file+".CONTENTS"):
1633 os.remove(file+".CONTENTS")
1634 if "contents" in self.settings:
1635 if os.path.exists(file):
1636 myf=open(file+".CONTENTS","w")
1638 for i in self.settings["contents"].split():
1643 contents=generate_contents(file,contents_function=j,\
1644 verbose="VERBOSE" in self.settings)
1649 def gen_digest_file(self,file):
1650 if os.path.exists(file+".DIGESTS"):
1651 os.remove(file+".DIGESTS")
1652 if "digests" in self.settings:
1653 if os.path.exists(file):
1654 myf=open(file+".DIGESTS","w")
1656 for i in self.settings["digests"].split():
1660 for f in [file, file+'.CONTENTS']:
1661 if os.path.exists(f):
1663 for k in hash_map.keys():
1664 hash=generate_hash(f,hash_function=k,verbose=\
1665 "VERBOSE" in self.settings)
1669 hash=generate_hash(f,hash_function=j,verbose=\
1670 "VERBOSE" in self.settings)
1675 countdown(10,"Purging Caches ...")
1676 if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
1677 print "clearing autoresume ..."
1678 self.clear_autoresume()
1680 print "clearing chroot ..."
1683 if "PURGETMPONLY" not in self.settings:
1684 print "clearing package cache ..."
1685 self.clear_packages()
1687 print "clearing kerncache ..."
1688 self.clear_kerncache()
1690 # vim: ts=4 sw=4 sta et sts=4 ai