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 -I lbzip2 -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 -I lbzip2 -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 """ Setup the portage overlay """
1068 if "portage_overlay" in self.settings:
1069 myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
1072 cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
1073 self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
1074 "Could not backup /etc/portage/make.conf",env=self.env)
1075 touch(self.settings["autoresume_path"]+"chroot_setup")
1078 if "AUTORESUME" in self.settings \
1079 and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
1080 print "Resume point detected, skipping fsscript operation..."
1082 if "fsscript" in self.settings:
1083 if os.path.exists(self.settings["controller_file"]):
1084 cmd("/bin/bash "+self.settings["controller_file"]+\
1085 " fsscript","fsscript script failed.",env=self.env)
1086 touch(self.settings["autoresume_path"]+"fsscript")
1089 if "AUTORESUME" in self.settings \
1090 and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
1091 print "Resume point detected, skipping rcupdate operation..."
1093 if os.path.exists(self.settings["controller_file"]):
1094 cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
1095 "rc-update script failed.",env=self.env)
1096 touch(self.settings["autoresume_path"]+"rcupdate")
1099 if "AUTORESUME" in self.settings \
1100 and os.path.exists(self.settings["autoresume_path"]+"clean"):
1101 print "Resume point detected, skipping clean operation..."
1103 for x in self.settings["cleanables"]:
1104 print "Cleaning chroot: "+x+"... "
1105 cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
1108 """ Put /etc/hosts back into place """
1109 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
1110 cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
1111 self.settings["chroot_path"]+"/etc/hosts",\
1112 "Could not replace /etc/hosts",env=self.env)
1114 """ Remove our overlay """
1115 if os.path.exists(self.settings["chroot_path"]+"/usr/local/portage"):
1116 cmd("rm -rf "+self.settings["chroot_path"]+"/usr/local/portage",\
1117 "Could not remove /usr/local/portage",env=self.env)
1118 cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
1119 "/etc/portage/make.conf",\
1120 "Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
1122 """ Clean up old and obsoleted files in /etc """
1123 if os.path.exists(self.settings["stage_path"]+"/etc"):
1124 cmd("find "+self.settings["stage_path"]+\
1125 "/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
1126 "Could not remove stray files in /etc",env=self.env)
1128 if os.path.exists(self.settings["controller_file"]):
1129 cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
1130 "clean script failed.",env=self.env)
1131 touch(self.settings["autoresume_path"]+"clean")
1134 if "AUTORESUME" in self.settings \
1135 and os.path.exists(self.settings["autoresume_path"]+"empty"):
1136 print "Resume point detected, skipping empty operation..."
1138 if self.settings["spec_prefix"]+"/empty" in self.settings:
1139 if type(self.settings[self.settings["spec_prefix"]+\
1140 "/empty"])==types.StringType:
1141 self.settings[self.settings["spec_prefix"]+"/empty"]=\
1142 self.settings[self.settings["spec_prefix"]+\
1144 for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
1145 myemp=self.settings["destpath"]+x
1146 if not os.path.isdir(myemp) or os.path.islink(myemp):
1147 print x,"not a directory or does not exist, skipping 'empty' operation."
1149 print "Emptying directory",x
1151 stat the dir, delete the dir, recreate the dir and set
1152 the proper perms and ownership
1154 mystat=os.stat(myemp)
1155 shutil.rmtree(myemp)
1156 os.makedirs(myemp,0755)
1157 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1158 os.chmod(myemp,mystat[ST_MODE])
1159 touch(self.settings["autoresume_path"]+"empty")
1162 if "AUTORESUME" in self.settings \
1163 and os.path.exists(self.settings["autoresume_path"]+"remove"):
1164 print "Resume point detected, skipping remove operation..."
1166 if self.settings["spec_prefix"]+"/rm" in self.settings:
1167 for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
1169 We're going to shell out for all these cleaning
1170 operations, so we get easy glob handling.
1172 print "livecd: removing "+x
1173 os.system("rm -rf "+self.settings["chroot_path"]+x)
1175 if os.path.exists(self.settings["controller_file"]):
1176 cmd("/bin/bash "+self.settings["controller_file"]+\
1177 " clean","Clean failed.",env=self.env)
1178 touch(self.settings["autoresume_path"]+"remove")
1184 if "AUTORESUME" in self.settings \
1185 and os.path.exists(self.settings["autoresume_path"]+"preclean"):
1186 print "Resume point detected, skipping preclean operation..."
1189 if os.path.exists(self.settings["controller_file"]):
1190 cmd("/bin/bash "+self.settings["controller_file"]+\
1191 " preclean","preclean script failed.",env=self.env)
1192 touch(self.settings["autoresume_path"]+"preclean")
1196 raise CatalystError, "Build failed, could not execute preclean"
1199 if "AUTORESUME" in self.settings \
1200 and os.path.exists(self.settings["autoresume_path"]+"capture"):
1201 print "Resume point detected, skipping capture operation..."
1203 """ Capture target in a tarball """
1204 mypath=self.settings["target_path"].split("/")
1205 """ Remove filename from path """
1206 mypath=string.join(mypath[:-1],"/")
1208 """ Now make sure path exists """
1209 if not os.path.exists(mypath):
1212 print "Creating stage tarball..."
1214 cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
1215 self.settings["stage_path"]+" .",\
1216 "Couldn't create stage tarball",env=self.env)
1218 self.gen_contents_file(self.settings["target_path"])
1219 self.gen_digest_file(self.settings["target_path"])
1221 touch(self.settings["autoresume_path"]+"capture")
1223 def run_local(self):
1224 if "AUTORESUME" in self.settings \
1225 and os.path.exists(self.settings["autoresume_path"]+"run_local"):
1226 print "Resume point detected, skipping run_local operation..."
1229 if os.path.exists(self.settings["controller_file"]):
1230 cmd("/bin/bash "+self.settings["controller_file"]+" run",\
1231 "run script failed.",env=self.env)
1232 touch(self.settings["autoresume_path"]+"run_local")
1234 except CatalystError:
1236 raise CatalystError,"Stage build aborting due to error."
1238 def setup_environment(self):
1240 Modify the current environment. This is an ugly hack that should be
1241 fixed. We need this to use the os.system() call since we can't
1242 specify our own environ
1244 for x in self.settings.keys():
1245 """ Sanitize var names by doing "s|/-.|_|g" """
1246 varname="clst_"+string.replace(x,"/","_")
1247 varname=string.replace(varname,"-","_")
1248 varname=string.replace(varname,".","_")
1249 if type(self.settings[x])==types.StringType:
1250 """ Prefix to prevent namespace clashes """
1251 #os.environ[varname]=self.settings[x]
1252 self.env[varname]=self.settings[x]
1253 elif type(self.settings[x])==types.ListType:
1254 #os.environ[varname]=string.join(self.settings[x])
1255 self.env[varname]=string.join(self.settings[x])
1256 elif type(self.settings[x])==types.BooleanType:
1257 if self.settings[x]:
1258 self.env[varname]="true"
1260 self.env[varname]="false"
1261 if "makeopts" in self.settings:
1262 self.env["MAKEOPTS"]=self.settings["makeopts"]
1265 self.chroot_lock.write_lock()
1267 """ Kill any pids in the chroot "" """
1268 self.kill_chroot_pids()
1270 """ Check for mounts right away and abort if we cannot unmount them """
1271 self.mount_safety_check()
1273 if "CLEAR_AUTORESUME" in self.settings:
1274 self.clear_autoresume()
1276 if "PURGETMPONLY" in self.settings:
1280 if "PURGEONLY" in self.settings:
1284 if "PURGE" in self.settings:
1287 for x in self.settings["action_sequence"]:
1288 print "--- Running action sequence: "+x
1291 apply(getattr(self,x))
1293 self.mount_safety_check()
1296 self.chroot_lock.unlock()
1299 if "AUTORESUME" in self.settings \
1300 and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
1301 print "Resume point detected, skipping unmerge operation..."
1303 if self.settings["spec_prefix"]+"/unmerge" in self.settings:
1304 if type(self.settings[self.settings["spec_prefix"]+\
1305 "/unmerge"])==types.StringType:
1306 self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
1307 [self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1309 self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1311 for x in range(0,len(myunmerge)):
1313 Surround args with quotes for passing to bash, allows
1314 things like "<" to remain intact
1316 myunmerge[x]="'"+myunmerge[x]+"'"
1317 myunmerge=string.join(myunmerge)
1319 """ Before cleaning, unmerge stuff """
1321 cmd("/bin/bash "+self.settings["controller_file"]+\
1322 " unmerge "+ myunmerge,"Unmerge script failed.",\
1324 print "unmerge shell script"
1325 except CatalystError:
1328 touch(self.settings["autoresume_path"]+"unmerge")
1330 def target_setup(self):
1331 if "AUTORESUME" in self.settings \
1332 and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
1333 print "Resume point detected, skipping target_setup operation..."
1335 print "Setting up filesystems per filesystem type"
1336 cmd("/bin/bash "+self.settings["controller_file"]+\
1337 " target_image_setup "+ self.settings["target_path"],\
1338 "target_image_setup script failed.",env=self.env)
1339 touch(self.settings["autoresume_path"]+"target_setup")
1341 def setup_overlay(self):
1342 if "AUTORESUME" in self.settings \
1343 and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
1344 print "Resume point detected, skipping setup_overlay operation..."
1346 if self.settings["spec_prefix"]+"/overlay" in self.settings:
1347 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
1348 if os.path.exists(x):
1349 cmd("rsync -a "+x+"/ "+\
1350 self.settings["target_path"],\
1351 self.settings["spec_prefix"]+"overlay: "+x+\
1352 " copy failed.",env=self.env)
1353 touch(self.settings["autoresume_path"]+"setup_overlay")
1355 def create_iso(self):
1356 if "AUTORESUME" in self.settings \
1357 and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
1358 print "Resume point detected, skipping create_iso operation..."
1360 """ Create the ISO """
1361 if "iso" in self.settings:
1362 cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1363 self.settings["iso"],"ISO creation script failed.",\
1365 self.gen_contents_file(self.settings["iso"])
1366 self.gen_digest_file(self.settings["iso"])
1367 touch(self.settings["autoresume_path"]+"create_iso")
1369 print "WARNING: livecd/iso was not defined."
1370 print "An ISO Image will not be created."
1372 def build_packages(self):
1373 if "AUTORESUME" in self.settings \
1374 and os.path.exists(self.settings["autoresume_path"]+\
1376 print "Resume point detected, skipping build_packages operation..."
1378 if self.settings["spec_prefix"]+"/packages" in self.settings:
1379 if "AUTORESUME" in self.settings \
1380 and os.path.exists(self.settings["autoresume_path"]+\
1382 print "Resume point detected, skipping build_packages operation..."
1385 list_bashify(self.settings[self.settings["spec_prefix"]\
1388 cmd("/bin/bash "+self.settings["controller_file"]+\
1389 " build_packages "+mypack,\
1390 "Error in attempt to build packages",env=self.env)
1391 touch(self.settings["autoresume_path"]+"build_packages")
1392 except CatalystError:
1394 raise CatalystError,self.settings["spec_prefix"]+\
1395 "build aborting due to error."
1397 def build_kernel(self):
1398 "Build all configured kernels"
1399 if "AUTORESUME" in self.settings \
1400 and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
1401 print "Resume point detected, skipping build_kernel operation..."
1403 if "boot/kernel" in self.settings:
1405 mynames=self.settings["boot/kernel"]
1406 if type(mynames)==types.StringType:
1409 Execute the script that sets up the kernel build environment
1411 cmd("/bin/bash "+self.settings["controller_file"]+\
1412 " pre-kmerge ","Runscript pre-kmerge failed",\
1414 for kname in mynames:
1415 self._build_kernel(kname=kname)
1416 touch(self.settings["autoresume_path"]+"build_kernel")
1417 except CatalystError:
1419 raise CatalystError,\
1420 "build aborting due to kernel build error."
1422 def _build_kernel(self, kname):
1423 "Build a single configured kernel by name"
1424 if "AUTORESUME" in self.settings \
1425 and os.path.exists(self.settings["autoresume_path"]\
1426 +"build_kernel_"+kname):
1427 print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1429 self._copy_kernel_config(kname=kname)
1432 If we need to pass special options to the bootloader
1433 for this kernel put them into the environment
1435 if "boot/kernel/"+kname+"/kernelopts" in self.settings:
1436 myopts=self.settings["boot/kernel/"+kname+\
1439 if type(myopts) != types.StringType:
1440 myopts = string.join(myopts)
1441 self.env[kname+"_kernelopts"]=myopts
1444 self.env[kname+"_kernelopts"]=""
1446 if "boot/kernel/"+kname+"/extraversion" not in self.settings:
1447 self.settings["boot/kernel/"+kname+\
1450 self.env["clst_kextraversion"]=\
1451 self.settings["boot/kernel/"+kname+\
1454 self._copy_initramfs_overlay(kname=kname)
1456 """ Execute the script that builds the kernel """
1457 cmd("/bin/bash "+self.settings["controller_file"]+\
1459 "Runscript kernel build failed",env=self.env)
1461 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1462 if os.path.exists(self.settings["chroot_path"]+\
1463 "/tmp/initramfs_overlay/"):
1464 print "Cleaning up temporary overlay dir"
1465 cmd("rm -R "+self.settings["chroot_path"]+\
1466 "/tmp/initramfs_overlay/",env=self.env)
1468 touch(self.settings["autoresume_path"]+\
1469 "build_kernel_"+kname)
1472 Execute the script that cleans up the kernel build
1475 cmd("/bin/bash "+self.settings["controller_file"]+\
1477 "Runscript post-kmerge failed",env=self.env)
1479 def _copy_kernel_config(self, kname):
1480 if "boot/kernel/"+kname+"/config" in self.settings:
1481 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1483 raise CatalystError,\
1484 "Can't find kernel config: "+\
1485 self.settings["boot/kernel/"+kname+\
1489 cmd("cp "+self.settings["boot/kernel/"+kname+\
1491 self.settings["chroot_path"]+"/var/tmp/"+\
1493 "Couldn't copy kernel config: "+\
1494 self.settings["boot/kernel/"+kname+\
1495 "/config"],env=self.env)
1497 except CatalystError:
1500 def _copy_initramfs_overlay(self, kname):
1501 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1502 if os.path.exists(self.settings["boot/kernel/"+\
1503 kname+"/initramfs_overlay"]):
1504 print "Copying initramfs_overlay dir "+\
1505 self.settings["boot/kernel/"+kname+\
1506 "/initramfs_overlay"]
1509 self.settings["chroot_path"]+\
1510 "/tmp/initramfs_overlay/"+\
1511 self.settings["boot/kernel/"+kname+\
1512 "/initramfs_overlay"],env=self.env)
1514 cmd("cp -R "+self.settings["boot/kernel/"+\
1515 kname+"/initramfs_overlay"]+"/* "+\
1516 self.settings["chroot_path"]+\
1517 "/tmp/initramfs_overlay/"+\
1518 self.settings["boot/kernel/"+kname+\
1519 "/initramfs_overlay"],env=self.env)
1521 def bootloader(self):
1522 if "AUTORESUME" in self.settings \
1523 and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
1524 print "Resume point detected, skipping bootloader operation..."
1527 cmd("/bin/bash "+self.settings["controller_file"]+\
1528 " bootloader " + self.settings["target_path"],\
1529 "Bootloader script failed.",env=self.env)
1530 touch(self.settings["autoresume_path"]+"bootloader")
1531 except CatalystError:
1533 raise CatalystError,"Script aborting due to error."
1535 def livecd_update(self):
1536 if "AUTORESUME" in self.settings \
1537 and os.path.exists(self.settings["autoresume_path"]+\
1539 print "Resume point detected, skipping build_packages operation..."
1542 cmd("/bin/bash "+self.settings["controller_file"]+\
1543 " livecd-update","livecd-update failed.",env=self.env)
1544 touch(self.settings["autoresume_path"]+"livecd_update")
1546 except CatalystError:
1548 raise CatalystError,"build aborting due to livecd_update error."
1550 def clear_chroot(self):
1551 myemp=self.settings["chroot_path"]
1552 if os.path.isdir(myemp):
1553 print "Emptying directory",myemp
1555 stat the dir, delete the dir, recreate the dir and set
1556 the proper perms and ownership
1558 mystat=os.stat(myemp)
1559 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1560 """ There's no easy way to change flags recursively in python """
1561 if os.uname()[0] == "FreeBSD":
1562 os.system("chflags -R noschg "+myemp)
1563 shutil.rmtree(myemp)
1564 os.makedirs(myemp,0755)
1565 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1566 os.chmod(myemp,mystat[ST_MODE])
1568 def clear_packages(self):
1569 if "PKGCACHE" in self.settings:
1570 print "purging the pkgcache ..."
1572 myemp=self.settings["pkgcache_path"]
1573 if os.path.isdir(myemp):
1574 print "Emptying directory",myemp
1576 stat the dir, delete the dir, recreate the dir and set
1577 the proper perms and ownership
1579 mystat=os.stat(myemp)
1580 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1581 shutil.rmtree(myemp)
1582 os.makedirs(myemp,0755)
1583 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1584 os.chmod(myemp,mystat[ST_MODE])
1586 def clear_kerncache(self):
1587 if "KERNCACHE" in self.settings:
1588 print "purging the kerncache ..."
1590 myemp=self.settings["kerncache_path"]
1591 if os.path.isdir(myemp):
1592 print "Emptying directory",myemp
1594 stat the dir, delete the dir, recreate the dir and set
1595 the proper perms and ownership
1597 mystat=os.stat(myemp)
1598 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1599 shutil.rmtree(myemp)
1600 os.makedirs(myemp,0755)
1601 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1602 os.chmod(myemp,mystat[ST_MODE])
1604 def clear_autoresume(self):
1605 """ Clean resume points since they are no longer needed """
1606 if "AUTORESUME" in self.settings:
1607 print "Removing AutoResume Points: ..."
1608 myemp=self.settings["autoresume_path"]
1609 if os.path.isdir(myemp):
1610 if "AUTORESUME" in self.settings:
1611 print "Emptying directory",myemp
1613 stat the dir, delete the dir, recreate the dir and set
1614 the proper perms and ownership
1616 mystat=os.stat(myemp)
1617 if os.uname()[0] == "FreeBSD":
1618 cmd("chflags -R noschg "+myemp,\
1619 "Could not remove immutable flag for file "\
1621 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1622 shutil.rmtree(myemp)
1623 os.makedirs(myemp,0755)
1624 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1625 os.chmod(myemp,mystat[ST_MODE])
1627 def gen_contents_file(self,file):
1628 if os.path.exists(file+".CONTENTS"):
1629 os.remove(file+".CONTENTS")
1630 if "contents" in self.settings:
1631 if os.path.exists(file):
1632 myf=open(file+".CONTENTS","w")
1634 for i in self.settings["contents"].split():
1639 contents=generate_contents(file,contents_function=j,\
1640 verbose="VERBOSE" in self.settings)
1645 def gen_digest_file(self,file):
1646 if os.path.exists(file+".DIGESTS"):
1647 os.remove(file+".DIGESTS")
1648 if "digests" in self.settings:
1649 if os.path.exists(file):
1650 myf=open(file+".DIGESTS","w")
1652 for i in self.settings["digests"].split():
1656 for f in [file, file+'.CONTENTS']:
1657 if os.path.exists(f):
1659 for k in hash_map.keys():
1660 hash=generate_hash(f,hash_function=k,verbose=\
1661 "VERBOSE" in self.settings)
1665 hash=generate_hash(f,hash_function=j,verbose=\
1666 "VERBOSE" in self.settings)
1671 countdown(10,"Purging Caches ...")
1672 if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
1673 print "clearing autoresume ..."
1674 self.clear_autoresume()
1676 print "clearing chroot ..."
1679 if "PURGETMPONLY" not in self.settings:
1680 print "clearing package cache ..."
1681 self.clear_packages()
1683 print "clearing kerncache ..."
1684 self.clear_kerncache()
1686 # vim: ts=4 sw=4 sta et sts=4 ai