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", "distdir", "port_tmpdir"]
183 self.mountmap = {"proc":"/proc", "dev":"/dev", "devpts":"/dev/pts",
184 "distdir":self.settings["distdir"], "port_tmpdir":"tmpfs"}
185 if os.uname()[0] == "Linux":
186 self.mounts.append("devpts")
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("packagedir")
199 self.mountmap["packagedir"] = self.settings["pkgcache_path"]
201 if "KERNCACHE" in self.settings:
202 self.set_kerncache_path()
203 print "Location of the kerncache is "+\
204 self.settings["kerncache_path"]
205 self.mounts.append("kerncache")
206 self.mountmap["kerncache"] = self.settings["kerncache_path"]
208 if "CCACHE" in self.settings:
209 if "CCACHE_DIR" in os.environ:
210 ccdir=os.environ["CCACHE_DIR"]
211 del os.environ["CCACHE_DIR"]
213 ccdir="/root/.ccache"
214 if not os.path.isdir(ccdir):
215 raise CatalystError,\
216 "Compiler cache support can't be enabled (can't find "+\
218 self.mounts.append("ccache")
219 self.mountmap["ccache"] = ccdir
220 """ for the chroot: """
221 self.env["CCACHE_DIR"]="/var/tmp/ccache"
223 if "ICECREAM" in self.settings:
224 self.mounts.append("/var/cache/icecream")
225 self.mountmap["/var/cache/icecream"]="/var/cache/icecream"
226 self.env["PATH"]="/usr/lib/icecc/bin:"+self.env["PATH"]
228 if "port_logdir" in self.settings:
229 self.mounts.append("/var/log/portage")
230 self.mountmap["/var/log/portage"]=self.settings["port_logdir"]
231 self.env["PORT_LOGDIR"]="/var/log/portage"
232 self.env["PORT_LOGDIR_CLEAN"]='find "${PORT_LOGDIR}" -type f ! -name "summary.log*" -mtime +30 -delete'
234 def override_cbuild(self):
235 if "CBUILD" in self.makeconf:
236 self.settings["CBUILD"]=self.makeconf["CBUILD"]
238 def override_chost(self):
239 if "CHOST" in self.makeconf:
240 self.settings["CHOST"]=self.makeconf["CHOST"]
242 def override_cflags(self):
243 if "CFLAGS" in self.makeconf:
244 self.settings["CFLAGS"]=self.makeconf["CFLAGS"]
246 def override_cxxflags(self):
247 if "CXXFLAGS" in self.makeconf:
248 self.settings["CXXFLAGS"]=self.makeconf["CXXFLAGS"]
250 def override_ldflags(self):
251 if "LDFLAGS" in self.makeconf:
252 self.settings["LDFLAGS"]=self.makeconf["LDFLAGS"]
254 def set_install_mask(self):
255 if "install_mask" in self.settings:
256 if type(self.settings["install_mask"])!=types.StringType:
257 self.settings["install_mask"]=\
258 string.join(self.settings["install_mask"])
260 def set_spec_prefix(self):
261 self.settings["spec_prefix"]=self.settings["target"]
263 def set_target_profile(self):
264 self.settings["target_profile"]=self.settings["profile"]
266 def set_target_subpath(self):
267 self.settings["target_subpath"]=self.settings["rel_type"]+"/"+\
268 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
269 self.settings["version_stamp"]
271 def set_source_subpath(self):
272 if type(self.settings["source_subpath"])!=types.StringType:
273 raise CatalystError,\
274 "source_subpath should have been a string. Perhaps you have something wrong in your spec file?"
276 def set_pkgcache_path(self):
277 if "pkgcache_path" in self.settings:
278 if type(self.settings["pkgcache_path"])!=types.StringType:
279 self.settings["pkgcache_path"]=\
280 normpath(string.join(self.settings["pkgcache_path"]))
282 self.settings["pkgcache_path"]=\
283 normpath(self.settings["storedir"]+"/packages/"+\
284 self.settings["target_subpath"]+"/")
286 def set_kerncache_path(self):
287 if "kerncache_path" in self.settings:
288 if type(self.settings["kerncache_path"])!=types.StringType:
289 self.settings["kerncache_path"]=\
290 normpath(string.join(self.settings["kerncache_path"]))
292 self.settings["kerncache_path"]=normpath(self.settings["storedir"]+\
293 "/kerncache/"+self.settings["target_subpath"]+"/")
295 def set_target_path(self):
296 self.settings["target_path"]=normpath(self.settings["storedir"]+\
297 "/builds/"+self.settings["target_subpath"]+".tar.bz2")
298 if "AUTORESUME" in self.settings\
299 and os.path.exists(self.settings["autoresume_path"]+\
300 "setup_target_path"):
302 "Resume point detected, skipping target path setup operation..."
304 """ First clean up any existing target stuff """
305 # XXX WTF are we removing the old tarball before we start building the
306 # XXX new one? If the build fails, you don't want to be left with
308 # if os.path.isfile(self.settings["target_path"]):
309 # cmd("rm -f "+self.settings["target_path"],\
310 # "Could not remove existing file: "\
311 # +self.settings["target_path"],env=self.env)
312 touch(self.settings["autoresume_path"]+"setup_target_path")
314 if not os.path.exists(self.settings["storedir"]+"/builds/"):
315 os.makedirs(self.settings["storedir"]+"/builds/")
317 def set_fsscript(self):
318 if self.settings["spec_prefix"]+"/fsscript" in self.settings:
319 self.settings["fsscript"]=\
320 self.settings[self.settings["spec_prefix"]+"/fsscript"]
321 del self.settings[self.settings["spec_prefix"]+"/fsscript"]
324 if self.settings["spec_prefix"]+"/rcadd" in self.settings:
325 self.settings["rcadd"]=\
326 self.settings[self.settings["spec_prefix"]+"/rcadd"]
327 del self.settings[self.settings["spec_prefix"]+"/rcadd"]
330 if self.settings["spec_prefix"]+"/rcdel" in self.settings:
331 self.settings["rcdel"]=\
332 self.settings[self.settings["spec_prefix"]+"/rcdel"]
333 del self.settings[self.settings["spec_prefix"]+"/rcdel"]
336 if self.settings["spec_prefix"]+"/cdtar" in self.settings:
337 self.settings["cdtar"]=\
338 normpath(self.settings[self.settings["spec_prefix"]+"/cdtar"])
339 del self.settings[self.settings["spec_prefix"]+"/cdtar"]
342 if self.settings["spec_prefix"]+"/iso" in self.settings:
343 if self.settings[self.settings["spec_prefix"]+"/iso"].startswith('/'):
344 self.settings["iso"]=\
345 normpath(self.settings[self.settings["spec_prefix"]+"/iso"])
347 # This automatically prepends the build dir to the ISO output path
348 # if it doesn't start with a /
349 self.settings["iso"] = normpath(self.settings["storedir"] + \
350 "/builds/" + self.settings["rel_type"] + "/" + \
351 self.settings[self.settings["spec_prefix"]+"/iso"])
352 del self.settings[self.settings["spec_prefix"]+"/iso"]
354 def set_fstype(self):
355 if self.settings["spec_prefix"]+"/fstype" in self.settings:
356 self.settings["fstype"]=\
357 self.settings[self.settings["spec_prefix"]+"/fstype"]
358 del self.settings[self.settings["spec_prefix"]+"/fstype"]
360 if "fstype" not in self.settings:
361 self.settings["fstype"]="normal"
362 for x in self.valid_values:
363 if x == self.settings["spec_prefix"]+"/fstype":
364 print "\n"+self.settings["spec_prefix"]+\
365 "/fstype is being set to the default of \"normal\"\n"
368 if "fstype" in self.settings:
369 self.valid_values.append("fsops")
370 if self.settings["spec_prefix"]+"/fsops" in self.settings:
371 self.settings["fsops"]=\
372 self.settings[self.settings["spec_prefix"]+"/fsops"]
373 del self.settings[self.settings["spec_prefix"]+"/fsops"]
375 def set_source_path(self):
376 if "SEEDCACHE" in self.settings\
377 and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+\
378 self.settings["source_subpath"]+"/")):
379 self.settings["source_path"]=normpath(self.settings["storedir"]+\
380 "/tmp/"+self.settings["source_subpath"]+"/")
382 self.settings["source_path"]=normpath(self.settings["storedir"]+\
383 "/builds/"+self.settings["source_subpath"]+".tar.bz2")
384 if os.path.isfile(self.settings["source_path"]):
385 # XXX: Is this even necessary if the previous check passes?
386 if os.path.exists(self.settings["source_path"]):
387 self.settings["source_path_hash"]=\
388 generate_hash(self.settings["source_path"],\
389 hash_function=self.settings["hash_function"],\
391 print "Source path set to "+self.settings["source_path"]
392 if os.path.isdir(self.settings["source_path"]):
393 print "\tIf this is not desired, remove this directory or turn off"
394 print "\tseedcache in the options of catalyst.conf the source path"
395 print "\twill then be "+\
396 normpath(self.settings["storedir"]+"/builds/"+\
397 self.settings["source_subpath"]+".tar.bz2\n")
399 def set_dest_path(self):
400 if "root_path" in self.settings:
401 self.settings["destpath"]=normpath(self.settings["chroot_path"]+\
402 self.settings["root_path"])
404 self.settings["destpath"]=normpath(self.settings["chroot_path"])
406 def set_cleanables(self):
407 self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/tmp/*",\
408 "/root/*", self.settings["portdir"]]
410 def set_snapshot_path(self):
411 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
412 "/snapshots/" + self.settings["snapshot_name"] +
413 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/" + self.settings["snapshot_name"] +
422 self.settings["snapshot"] + ".tar.bz2")
424 if os.path.exists(self.settings["snapshot_path"]):
425 self.settings["snapshot_path_hash"]=\
426 generate_hash(self.settings["snapshot_path"],\
427 hash_function=self.settings["hash_function"],verbose=False)
429 def set_snapcache_path(self):
430 if "SNAPCACHE" in self.settings:
431 self.settings["snapshot_cache_path"]=\
432 normpath(self.settings["snapshot_cache"]+"/"+\
433 self.settings["snapshot"]+"/")
434 self.snapcache_lock=\
435 catalyst_lock.LockDir(self.settings["snapshot_cache_path"])
436 print "Caching snapshot to "+self.settings["snapshot_cache_path"]
438 def set_chroot_path(self):
440 NOTE: the trailing slash is very important!
441 Things *will* break without it!
443 self.settings["chroot_path"]=normpath(self.settings["storedir"]+\
444 "/tmp/"+self.settings["target_subpath"]+"/")
445 self.chroot_lock=catalyst_lock.LockDir(self.settings["chroot_path"])
447 def set_autoresume_path(self):
448 self.settings["autoresume_path"]=normpath(self.settings["storedir"]+\
449 "/tmp/"+self.settings["rel_type"]+"/"+".autoresume-"+\
450 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
451 self.settings["version_stamp"]+"/")
452 if "AUTORESUME" in self.settings:
453 print "The autoresume path is " + self.settings["autoresume_path"]
454 if not os.path.exists(self.settings["autoresume_path"]):
455 os.makedirs(self.settings["autoresume_path"],0755)
457 def set_controller_file(self):
458 self.settings["controller_file"]=normpath(self.settings["sharedir"]+\
459 "/targets/"+self.settings["target"]+"/"+self.settings["target"]+\
462 def set_iso_volume_id(self):
463 if self.settings["spec_prefix"]+"/volid" in self.settings:
464 self.settings["iso_volume_id"]=\
465 self.settings[self.settings["spec_prefix"]+"/volid"]
466 if len(self.settings["iso_volume_id"])>32:
467 raise CatalystError,\
468 "ISO volume ID must not exceed 32 characters."
470 self.settings["iso_volume_id"]="catalyst "+self.settings["snapshot"]
472 def set_action_sequence(self):
473 """ Default action sequence for run method """
474 self.settings["action_sequence"]=["unpack","unpack_snapshot",\
475 "setup_confdir","portage_overlay",\
476 "base_dirs","bind","chroot_setup","setup_environment",\
477 "run_local","preclean","unbind","clean"]
478 # if "TARBALL" in self.settings or \
479 # "FETCH" not in self.settings:
480 if "FETCH" not in self.settings:
481 self.settings["action_sequence"].append("capture")
482 self.settings["action_sequence"].append("clear_autoresume")
485 if self.settings["spec_prefix"]+"/use" in self.settings:
486 self.settings["use"]=\
487 self.settings[self.settings["spec_prefix"]+"/use"]
488 del self.settings[self.settings["spec_prefix"]+"/use"]
489 if "use" not in self.settings:
490 self.settings["use"]=""
491 if type(self.settings["use"])==types.StringType:
492 self.settings["use"]=self.settings["use"].split()
494 # Force bindist when options ask for it
495 if "BINDIST" in self.settings:
496 self.settings["use"].append("bindist")
498 def set_stage_path(self):
499 self.settings["stage_path"]=normpath(self.settings["chroot_path"])
501 def set_mounts(self):
504 def set_packages(self):
508 if self.settings["spec_prefix"]+"/rm" in self.settings:
509 if type(self.settings[self.settings["spec_prefix"]+\
510 "/rm"])==types.StringType:
511 self.settings[self.settings["spec_prefix"]+"/rm"]=\
512 self.settings[self.settings["spec_prefix"]+"/rm"].split()
514 def set_linuxrc(self):
515 if self.settings["spec_prefix"]+"/linuxrc" in self.settings:
516 if type(self.settings[self.settings["spec_prefix"]+\
517 "/linuxrc"])==types.StringType:
518 self.settings["linuxrc"]=\
519 self.settings[self.settings["spec_prefix"]+"/linuxrc"]
520 del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
522 def set_busybox_config(self):
523 if self.settings["spec_prefix"]+"/busybox_config" in self.settings:
524 if type(self.settings[self.settings["spec_prefix"]+\
525 "/busybox_config"])==types.StringType:
526 self.settings["busybox_config"]=\
527 self.settings[self.settings["spec_prefix"]+"/busybox_config"]
528 del self.settings[self.settings["spec_prefix"]+"/busybox_config"]
530 def set_portage_overlay(self):
531 if "portage_overlay" in self.settings:
532 if type(self.settings["portage_overlay"])==types.StringType:
533 self.settings["portage_overlay"]=\
534 self.settings["portage_overlay"].split()
535 print "portage_overlay directories are set to: \""+\
536 string.join(self.settings["portage_overlay"])+"\""
538 def set_overlay(self):
539 if self.settings["spec_prefix"]+"/overlay" in self.settings:
540 if type(self.settings[self.settings["spec_prefix"]+\
541 "/overlay"])==types.StringType:
542 self.settings[self.settings["spec_prefix"]+"/overlay"]=\
543 self.settings[self.settings["spec_prefix"]+\
546 def set_root_overlay(self):
547 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
548 if type(self.settings[self.settings["spec_prefix"]+\
549 "/root_overlay"])==types.StringType:
550 self.settings[self.settings["spec_prefix"]+"/root_overlay"]=\
551 self.settings[self.settings["spec_prefix"]+\
552 "/root_overlay"].split()
554 def set_root_path(self):
555 """ ROOT= variable for emerges """
556 self.settings["root_path"]="/"
558 def set_valid_build_kernel_vars(self,addlargs):
559 if "boot/kernel" in addlargs:
560 if type(addlargs["boot/kernel"])==types.StringType:
561 loopy=[addlargs["boot/kernel"]]
563 loopy=addlargs["boot/kernel"]
566 self.valid_values.append("boot/kernel/"+x+"/aliases")
567 self.valid_values.append("boot/kernel/"+x+"/config")
568 self.valid_values.append("boot/kernel/"+x+"/console")
569 self.valid_values.append("boot/kernel/"+x+"/extraversion")
570 self.valid_values.append("boot/kernel/"+x+"/gk_action")
571 self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
572 self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
573 self.valid_values.append("boot/kernel/"+x+"/machine_type")
574 self.valid_values.append("boot/kernel/"+x+"/sources")
575 self.valid_values.append("boot/kernel/"+x+"/softlevel")
576 self.valid_values.append("boot/kernel/"+x+"/use")
577 self.valid_values.append("boot/kernel/"+x+"/packages")
578 if "boot/kernel/"+x+"/packages" in addlargs:
579 if type(addlargs["boot/kernel/"+x+\
580 "/packages"])==types.StringType:
581 addlargs["boot/kernel/"+x+"/packages"]=\
582 [addlargs["boot/kernel/"+x+"/packages"]]
584 def set_build_kernel_vars(self):
585 if self.settings["spec_prefix"]+"/gk_mainargs" in self.settings:
586 self.settings["gk_mainargs"]=\
587 self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
588 del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
590 def kill_chroot_pids(self):
591 print "Checking for processes running in chroot and killing them."
594 Force environment variables to be exported so script can see them
596 self.setup_environment()
598 if os.path.exists(self.settings["sharedir"]+\
599 "/targets/support/kill-chroot-pids.sh"):
600 cmd("/bin/bash "+self.settings["sharedir"]+\
601 "/targets/support/kill-chroot-pids.sh",\
602 "kill-chroot-pids script failed.",env=self.env)
604 def mount_safety_check(self):
605 mypath=self.settings["chroot_path"]
608 Check and verify that none of our paths in mypath are mounted. We don't
609 want to clean up with things still mounted, and this allows us to check.
610 Returns 1 on ok, 0 on "something is still mounted" case.
613 if not os.path.exists(mypath):
616 for x in self.mounts:
617 if not os.path.exists(mypath + self.mountmap[x]):
620 if ismount(mypath + self.mountmap[x]):
621 """ Something is still mounted "" """
623 print self.mountmap[x] + " is still mounted; performing auto-bind-umount...",
624 """ Try to umount stuff ourselves """
626 if ismount(mypath + self.mountmap[x]):
627 raise CatalystError, "Auto-unbind failed for " + self.mountmap[x]
629 print "Auto-unbind successful..."
630 except CatalystError:
631 raise CatalystError, "Unable to auto-unbind " + self.mountmap[x]
636 clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+\
639 if "SEEDCACHE" in self.settings:
640 if os.path.isdir(self.settings["source_path"]):
641 """ SEEDCACHE Is a directory, use rsync """
642 unpack_cmd="rsync -a --delete "+self.settings["source_path"]+\
643 " "+self.settings["chroot_path"]
644 display_msg="\nStarting rsync from "+\
645 self.settings["source_path"]+"\nto "+\
646 self.settings["chroot_path"]+\
647 " (This may take some time) ...\n"
648 error_msg="Rsync of "+self.settings["source_path"]+" to "+\
649 self.settings["chroot_path"]+" failed."
651 """ SEEDCACHE is a not a directory, try untar'ing """
652 print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
653 display_msg="\nStarting tar extract from "+\
654 self.settings["source_path"]+"\nto "+\
655 self.settings["chroot_path"]+\
656 " (This may take some time) ...\n"
657 if "bz2" == self.settings["chroot_path"][-3:]:
658 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
659 self.settings["chroot_path"]
661 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
662 self.settings["chroot_path"]
663 error_msg="Tarball extraction of "+\
664 self.settings["source_path"]+" to "+\
665 self.settings["chroot_path"]+" failed."
667 """ No SEEDCACHE, use tar """
668 display_msg="\nStarting tar extract from "+\
669 self.settings["source_path"]+"\nto "+\
670 self.settings["chroot_path"]+\
671 " (This may take some time) ...\n"
672 if "bz2" == self.settings["chroot_path"][-3:]:
673 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
674 self.settings["chroot_path"]
676 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
677 self.settings["chroot_path"]
678 error_msg="Tarball extraction of "+self.settings["source_path"]+\
679 " to "+self.settings["chroot_path"]+" failed."
681 if "AUTORESUME" in self.settings:
682 if os.path.isdir(self.settings["source_path"]) \
683 and os.path.exists(self.settings["autoresume_path"]+"unpack"):
684 """ Autoresume is valid, SEEDCACHE is valid """
686 invalid_snapshot=False
688 elif os.path.isfile(self.settings["source_path"]) \
689 and self.settings["source_path_hash"]==clst_unpack_hash:
690 """ Autoresume is valid, tarball is valid """
692 invalid_snapshot=True
694 elif os.path.isdir(self.settings["source_path"]) \
695 and not os.path.exists(self.settings["autoresume_path"]+\
697 """ Autoresume is invalid, SEEDCACHE """
699 invalid_snapshot=False
701 elif os.path.isfile(self.settings["source_path"]) \
702 and self.settings["source_path_hash"]!=clst_unpack_hash:
703 """ Autoresume is invalid, tarball """
705 invalid_snapshot=True
707 """ No autoresume, SEEDCACHE """
708 if "SEEDCACHE" in self.settings:
709 """ SEEDCACHE so let's run rsync and let it clean up """
710 if os.path.isdir(self.settings["source_path"]):
712 invalid_snapshot=False
713 elif os.path.isfile(self.settings["source_path"]):
714 """ Tarball so unpack and remove anything already there """
716 invalid_snapshot=True
717 """ No autoresume, no SEEDCACHE """
719 """ Tarball so unpack and remove anything already there """
720 if os.path.isfile(self.settings["source_path"]):
722 invalid_snapshot=True
723 elif os.path.isdir(self.settings["source_path"]):
724 """ We should never reach this, so something is very wrong """
725 raise CatalystError,\
726 "source path is a dir but seedcache is not enabled"
729 self.mount_safety_check()
732 if "AUTORESUME" in self.settings:
733 print "No Valid Resume point detected, cleaning up..."
735 self.clear_autoresume()
738 if not os.path.exists(self.settings["chroot_path"]):
739 os.makedirs(self.settings["chroot_path"])
741 if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
742 os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
744 if "PKGCACHE" in self.settings:
745 if not os.path.exists(self.settings["pkgcache_path"]):
746 os.makedirs(self.settings["pkgcache_path"],0755)
748 if "KERNCACHE" in self.settings:
749 if not os.path.exists(self.settings["kerncache_path"]):
750 os.makedirs(self.settings["kerncache_path"],0755)
753 cmd(unpack_cmd,error_msg,env=self.env)
755 if "source_path_hash" in self.settings:
756 myf=open(self.settings["autoresume_path"]+"unpack","w")
757 myf.write(self.settings["source_path_hash"])
760 touch(self.settings["autoresume_path"]+"unpack")
762 print "Resume point detected, skipping unpack operation..."
764 def unpack_snapshot(self):
766 snapshot_hash=read_from_clst(self.settings["autoresume_path"]+\
769 if "SNAPCACHE" in self.settings:
770 snapshot_cache_hash=\
771 read_from_clst(self.settings["snapshot_cache_path"]+\
773 destdir=self.settings["snapshot_cache_path"]
774 if "bz2" == self.settings["chroot_path"][-3:]:
775 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+destdir
777 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+destdir
778 unpack_errmsg="Error unpacking snapshot"
779 cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+\
780 self.settings["snapshot_cache_path"]+\
781 " (This can take a long time)..."
782 cleanup_errmsg="Error removing existing snapshot cache directory."
783 self.snapshot_lock_object=self.snapcache_lock
785 if self.settings["snapshot_path_hash"]==snapshot_cache_hash:
786 print "Valid snapshot cache, skipping unpack of portage tree..."
789 destdir = normpath(self.settings["chroot_path"] + self.settings["portdir"])
790 cleanup_errmsg="Error removing existing snapshot directory."
792 "Cleaning up existing portage tree (This can take a long time)..."
793 if "bz2" == self.settings["chroot_path"][-3:]:
794 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+\
795 self.settings["chroot_path"]+"/usr"
797 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+\
798 self.settings["chroot_path"]+"/usr"
799 unpack_errmsg="Error unpacking snapshot"
801 if "AUTORESUME" in self.settings \
802 and os.path.exists(self.settings["chroot_path"]+\
803 self.settings["portdir"]) \
804 and os.path.exists(self.settings["autoresume_path"]\
806 and self.settings["snapshot_path_hash"] == snapshot_hash:
808 "Valid Resume point detected, skipping unpack of portage tree..."
812 if "SNAPCACHE" in self.settings:
813 self.snapshot_lock_object.write_lock()
814 if os.path.exists(destdir):
816 cleanup_cmd="rm -rf "+destdir
817 cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
818 if not os.path.exists(destdir):
819 os.makedirs(destdir,0755)
821 print "Unpacking portage tree (This can take a long time) ..."
822 cmd(unpack_cmd,unpack_errmsg,env=self.env)
824 if "SNAPCACHE" in self.settings:
825 myf=open(self.settings["snapshot_cache_path"]+"catalyst-hash","w")
826 myf.write(self.settings["snapshot_path_hash"])
829 print "Setting snapshot autoresume point"
830 myf=open(self.settings["autoresume_path"]+"unpack_portage","w")
831 myf.write(self.settings["snapshot_path_hash"])
834 if "SNAPCACHE" in self.settings:
835 self.snapshot_lock_object.unlock()
837 def config_profile_link(self):
838 if "AUTORESUME" in self.settings \
839 and os.path.exists(self.settings["autoresume_path"]+\
840 "config_profile_link"):
842 "Resume point detected, skipping config_profile_link operation..."
844 # TODO: zmedico and I discussed making this a directory and pushing
845 # in a parent file, as well as other user-specified configuration.
846 print "Configuring profile link..."
847 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.profile",\
848 "Error zapping profile link",env=self.env)
849 cmd("mkdir -p "+self.settings["chroot_path"]+"/etc/portage/")
850 cmd("ln -sf ../.." + self.settings["portdir"] + "/profiles/" + \
851 self.settings["target_profile"]+" "+\
852 self.settings["chroot_path"]+"/etc/portage/make.profile",\
853 "Error creating profile link",env=self.env)
854 touch(self.settings["autoresume_path"]+"config_profile_link")
856 def setup_confdir(self):
857 if "AUTORESUME" in self.settings \
858 and os.path.exists(self.settings["autoresume_path"]+\
860 print "Resume point detected, skipping setup_confdir operation..."
862 if "portage_confdir" in self.settings:
863 print "Configuring /etc/portage..."
864 cmd("rsync -a "+self.settings["portage_confdir"]+"/ "+\
865 self.settings["chroot_path"]+"/etc/portage/",\
866 "Error copying /etc/portage",env=self.env)
867 touch(self.settings["autoresume_path"]+"setup_confdir")
869 def portage_overlay(self):
870 """ We copy the contents of our overlays to /usr/local/portage """
871 if "portage_overlay" in self.settings:
872 for x in self.settings["portage_overlay"]:
873 if os.path.exists(x):
874 print "Copying overlay dir " +x
875 cmd("mkdir -p "+self.settings["chroot_path"]+\
876 self.settings["local_overlay"],\
877 "Could not make portage_overlay dir",env=self.env)
878 cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+\
879 self.settings["local_overlay"],\
880 "Could not copy portage_overlay",env=self.env)
882 def root_overlay(self):
883 """ Copy over the root_overlay """
884 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
885 for x in self.settings[self.settings["spec_prefix"]+\
887 if os.path.exists(x):
888 print "Copying root_overlay: "+x
889 cmd("rsync -a "+x+"/ "+\
890 self.settings["chroot_path"],\
891 self.settings["spec_prefix"]+"/root_overlay: "+x+\
892 " copy failed.",env=self.env)
898 for x in self.mounts:
899 if not os.path.exists(self.settings["chroot_path"] + self.mountmap[x]):
900 os.makedirs(self.settings["chroot_path"]+x,0755)
902 if not os.path.exists(self.mountmap[x]):
903 if not self.mountmap[x] == "tmpfs":
904 os.makedirs(self.mountmap[x],0755)
907 if "SNAPCACHE" in self.settings and x == "/usr/portage":
908 self.snapshot_lock_object.read_lock()
909 if os.uname()[0] == "FreeBSD":
911 retval = os.system("mount -t devfs none " +
912 self.settings["chroot_path"] + src)
914 retval = os.system("mount_nullfs " + src + " " +
915 self.settings["chroot_path"] + src)
918 if "var_tmpfs_portage" in self.settings:
919 retval=os.system("mount -t tmpfs -o size="+\
920 self.settings["var_tmpfs_portage"]+"G "+src+" "+\
921 self.settings["chroot_path"]+x)
923 retval = os.system("mount --bind " + src + " " +
924 self.settings["chroot_path"] + src)
927 raise CatalystError,"Couldn't bind mount " + src
931 mypath=self.settings["chroot_path"]
932 myrevmounts=self.mounts[:]
933 myrevmounts.reverse()
934 """ Unmount in reverse order for nested bind-mounts """
935 for x in myrevmounts:
936 if not os.path.exists(mypath + self.mountmap[x]):
939 if not ismount(mypath + self.mountmap[x]):
942 retval=os.system("umount "+\
943 os.path.join(mypath, self.mountmap[x].lstrip(os.path.sep)))
946 warn("First attempt to unmount: " + mypath +
947 self.mountmap[x] +" failed.")
948 warn("Killing any pids still running in the chroot")
950 self.kill_chroot_pids()
952 retval2 = os.system("umount " + mypath + self.mountmap[x])
955 warn("Couldn't umount bind mount: " + mypath + self.mountmap[x])
957 if "SNAPCACHE" in self.settings and x == "/usr/portage":
960 It's possible the snapshot lock object isn't created yet.
961 This is because mount safety check calls unbind before the
962 target is fully initialized
964 self.snapshot_lock_object.unlock()
969 if any bind mounts really failed, then we need to raise
970 this to potentially prevent an upcoming bash stage cleanup script
971 from wiping our bind mounts.
973 raise CatalystError,\
974 "Couldn't umount one or more bind-mounts; aborting for safety."
976 def chroot_setup(self):
977 self.makeconf=read_makeconf(self.settings["chroot_path"]+\
978 "/etc/portage/make.conf")
979 self.override_cbuild()
980 self.override_chost()
981 self.override_cflags()
982 self.override_cxxflags()
983 self.override_ldflags()
984 if "AUTORESUME" in self.settings \
985 and os.path.exists(self.settings["autoresume_path"]+"chroot_setup"):
986 print "Resume point detected, skipping chroot_setup operation..."
988 print "Setting up chroot..."
990 #self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/portage/make.conf")
992 cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
993 "Could not copy resolv.conf into place.",env=self.env)
995 """ Copy over the envscript, if applicable """
996 if "ENVSCRIPT" in self.settings:
997 if not os.path.exists(self.settings["ENVSCRIPT"]):
998 raise CatalystError,\
999 "Can't find envscript "+self.settings["ENVSCRIPT"]
1001 print "\nWarning!!!!"
1002 print "\tOverriding certain env variables may cause catastrophic failure."
1003 print "\tIf your build fails look here first as the possible problem."
1004 print "\tCatalyst assumes you know what you are doing when setting"
1005 print "\t\tthese variables."
1006 print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
1007 print "\tYou have been warned\n"
1009 cmd("cp "+self.settings["ENVSCRIPT"]+" "+\
1010 self.settings["chroot_path"]+"/tmp/envscript",\
1011 "Could not copy envscript into place.",env=self.env)
1014 Copy over /etc/hosts from the host in case there are any
1015 specialties in there
1017 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
1018 cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+\
1019 self.settings["chroot_path"]+"/etc/hosts.catalyst",\
1020 "Could not backup /etc/hosts",env=self.env)
1021 cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts",\
1022 "Could not copy /etc/hosts",env=self.env)
1024 """ Modify and write out make.conf (for the chroot) """
1025 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.conf",\
1026 "Could not remove "+self.settings["chroot_path"]+\
1027 "/etc/portage/make.conf",env=self.env)
1028 myf=open(self.settings["chroot_path"]+"/etc/portage/make.conf","w")
1029 myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
1030 myf.write("# Please consult /usr/share/portage/config/make.conf.example for a more\n# detailed example.\n")
1031 if "CFLAGS" in self.settings:
1032 myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
1033 if "CXXFLAGS" in self.settings:
1034 if self.settings["CXXFLAGS"]!=self.settings["CFLAGS"]:
1035 myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
1037 myf.write('CXXFLAGS="${CFLAGS}"\n')
1039 myf.write('CXXFLAGS="${CFLAGS}"\n')
1041 if "LDFLAGS" in self.settings:
1042 myf.write("# LDFLAGS is unsupported. USE AT YOUR OWN RISK!\n")
1043 myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
1044 if "CBUILD" in self.settings:
1045 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")
1046 myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
1048 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")
1049 myf.write('CHOST="'+self.settings["CHOST"]+'"\n')
1051 """ Figure out what our USE vars are for building """
1053 if "HOSTUSE" in self.settings:
1054 myusevars.extend(self.settings["HOSTUSE"])
1056 if "use" in self.settings:
1057 myusevars.extend(self.settings["use"])
1060 myf.write("# These are the USE flags that were used in addition to what is provided by the\n# profile used for building.\n")
1061 myusevars = sorted(set(myusevars))
1062 myf.write('USE="'+string.join(myusevars)+'"\n')
1063 if '-*' in myusevars:
1064 print "\nWarning!!! "
1065 print "\tThe use of -* in "+self.settings["spec_prefix"]+\
1066 "/use will cause portage to ignore"
1067 print "\tpackage.use in the profile and portage_confdir. You've been warned!"
1069 myf.write('PORTDIR="%s"\n' % self.settings['portdir'])
1070 myf.write('DISTDIR="%s"\n' % self.settings['distdir'])
1071 myf.write('PKGDIR="%s"\n' % self.settings['packagedir'])
1073 """ Setup the portage overlay """
1074 if "portage_overlay" in self.settings:
1075 myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
1078 cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
1079 self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
1080 "Could not backup /etc/portage/make.conf",env=self.env)
1081 touch(self.settings["autoresume_path"]+"chroot_setup")
1084 if "AUTORESUME" in self.settings \
1085 and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
1086 print "Resume point detected, skipping fsscript operation..."
1088 if "fsscript" in self.settings:
1089 if os.path.exists(self.settings["controller_file"]):
1090 cmd("/bin/bash "+self.settings["controller_file"]+\
1091 " fsscript","fsscript script failed.",env=self.env)
1092 touch(self.settings["autoresume_path"]+"fsscript")
1095 if "AUTORESUME" in self.settings \
1096 and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
1097 print "Resume point detected, skipping rcupdate operation..."
1099 if os.path.exists(self.settings["controller_file"]):
1100 cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
1101 "rc-update script failed.",env=self.env)
1102 touch(self.settings["autoresume_path"]+"rcupdate")
1105 if "AUTORESUME" in self.settings \
1106 and os.path.exists(self.settings["autoresume_path"]+"clean"):
1107 print "Resume point detected, skipping clean operation..."
1109 for x in self.settings["cleanables"]:
1110 print "Cleaning chroot: "+x+"... "
1111 cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
1114 """ Put /etc/hosts back into place """
1115 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
1116 cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
1117 self.settings["chroot_path"]+"/etc/hosts",\
1118 "Could not replace /etc/hosts",env=self.env)
1120 """ Remove our overlay """
1121 if os.path.exists(self.settings["chroot_path"] + self.settings["local_overlay"]):
1122 cmd("rm -rf " + self.settings["chroot_path"] + self.settings["local_overlay"],
1123 "Could not remove " + self.settings["local_overlay"], env=self.env)
1124 cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
1125 "/etc/portage/make.conf",\
1126 "Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
1128 """ Clean up old and obsoleted files in /etc """
1129 if os.path.exists(self.settings["stage_path"]+"/etc"):
1130 cmd("find "+self.settings["stage_path"]+\
1131 "/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
1132 "Could not remove stray files in /etc",env=self.env)
1134 if os.path.exists(self.settings["controller_file"]):
1135 cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
1136 "clean script failed.",env=self.env)
1137 touch(self.settings["autoresume_path"]+"clean")
1140 if "AUTORESUME" in self.settings \
1141 and os.path.exists(self.settings["autoresume_path"]+"empty"):
1142 print "Resume point detected, skipping empty operation..."
1144 if self.settings["spec_prefix"]+"/empty" in self.settings:
1145 if type(self.settings[self.settings["spec_prefix"]+\
1146 "/empty"])==types.StringType:
1147 self.settings[self.settings["spec_prefix"]+"/empty"]=\
1148 self.settings[self.settings["spec_prefix"]+\
1150 for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
1151 myemp=self.settings["destpath"]+x
1152 if not os.path.isdir(myemp) or os.path.islink(myemp):
1153 print x,"not a directory or does not exist, skipping 'empty' operation."
1155 print "Emptying directory",x
1157 stat the dir, delete the dir, recreate the dir and set
1158 the proper perms and ownership
1160 mystat=os.stat(myemp)
1161 shutil.rmtree(myemp)
1162 os.makedirs(myemp,0755)
1163 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1164 os.chmod(myemp,mystat[ST_MODE])
1165 touch(self.settings["autoresume_path"]+"empty")
1168 if "AUTORESUME" in self.settings \
1169 and os.path.exists(self.settings["autoresume_path"]+"remove"):
1170 print "Resume point detected, skipping remove operation..."
1172 if self.settings["spec_prefix"]+"/rm" in self.settings:
1173 for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
1175 We're going to shell out for all these cleaning
1176 operations, so we get easy glob handling.
1178 print "livecd: removing "+x
1179 os.system("rm -rf "+self.settings["chroot_path"]+x)
1181 if os.path.exists(self.settings["controller_file"]):
1182 cmd("/bin/bash "+self.settings["controller_file"]+\
1183 " clean","Clean failed.",env=self.env)
1184 touch(self.settings["autoresume_path"]+"remove")
1190 if "AUTORESUME" in self.settings \
1191 and os.path.exists(self.settings["autoresume_path"]+"preclean"):
1192 print "Resume point detected, skipping preclean operation..."
1195 if os.path.exists(self.settings["controller_file"]):
1196 cmd("/bin/bash "+self.settings["controller_file"]+\
1197 " preclean","preclean script failed.",env=self.env)
1198 touch(self.settings["autoresume_path"]+"preclean")
1202 raise CatalystError, "Build failed, could not execute preclean"
1205 if "AUTORESUME" in self.settings \
1206 and os.path.exists(self.settings["autoresume_path"]+"capture"):
1207 print "Resume point detected, skipping capture operation..."
1209 """ Capture target in a tarball """
1210 mypath=self.settings["target_path"].split("/")
1211 """ Remove filename from path """
1212 mypath=string.join(mypath[:-1],"/")
1214 """ Now make sure path exists """
1215 if not os.path.exists(mypath):
1218 print "Creating stage tarball..."
1220 cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
1221 self.settings["stage_path"]+" .",\
1222 "Couldn't create stage tarball",env=self.env)
1224 self.gen_contents_file(self.settings["target_path"])
1225 self.gen_digest_file(self.settings["target_path"])
1227 touch(self.settings["autoresume_path"]+"capture")
1229 def run_local(self):
1230 if "AUTORESUME" in self.settings \
1231 and os.path.exists(self.settings["autoresume_path"]+"run_local"):
1232 print "Resume point detected, skipping run_local operation..."
1235 if os.path.exists(self.settings["controller_file"]):
1236 cmd("/bin/bash "+self.settings["controller_file"]+" run",\
1237 "run script failed.",env=self.env)
1238 touch(self.settings["autoresume_path"]+"run_local")
1240 except CatalystError:
1242 raise CatalystError,"Stage build aborting due to error."
1244 def setup_environment(self):
1246 Modify the current environment. This is an ugly hack that should be
1247 fixed. We need this to use the os.system() call since we can't
1248 specify our own environ
1250 for x in self.settings.keys():
1251 """ Sanitize var names by doing "s|/-.|_|g" """
1252 varname="clst_"+string.replace(x,"/","_")
1253 varname=string.replace(varname,"-","_")
1254 varname=string.replace(varname,".","_")
1255 if type(self.settings[x])==types.StringType:
1256 """ Prefix to prevent namespace clashes """
1257 #os.environ[varname]=self.settings[x]
1258 self.env[varname]=self.settings[x]
1259 elif type(self.settings[x])==types.ListType:
1260 #os.environ[varname]=string.join(self.settings[x])
1261 self.env[varname]=string.join(self.settings[x])
1262 elif type(self.settings[x])==types.BooleanType:
1263 if self.settings[x]:
1264 self.env[varname]="true"
1266 self.env[varname]="false"
1267 if "makeopts" in self.settings:
1268 self.env["MAKEOPTS"]=self.settings["makeopts"]
1271 self.chroot_lock.write_lock()
1273 """ Kill any pids in the chroot "" """
1274 self.kill_chroot_pids()
1276 """ Check for mounts right away and abort if we cannot unmount them """
1277 self.mount_safety_check()
1279 if "CLEAR_AUTORESUME" in self.settings:
1280 self.clear_autoresume()
1282 if "PURGETMPONLY" in self.settings:
1286 if "PURGEONLY" in self.settings:
1290 if "PURGE" in self.settings:
1293 for x in self.settings["action_sequence"]:
1294 print "--- Running action sequence: "+x
1297 apply(getattr(self,x))
1299 self.mount_safety_check()
1302 self.chroot_lock.unlock()
1305 if "AUTORESUME" in self.settings \
1306 and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
1307 print "Resume point detected, skipping unmerge operation..."
1309 if self.settings["spec_prefix"]+"/unmerge" in self.settings:
1310 if type(self.settings[self.settings["spec_prefix"]+\
1311 "/unmerge"])==types.StringType:
1312 self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
1313 [self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1315 self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1317 for x in range(0,len(myunmerge)):
1319 Surround args with quotes for passing to bash, allows
1320 things like "<" to remain intact
1322 myunmerge[x]="'"+myunmerge[x]+"'"
1323 myunmerge=string.join(myunmerge)
1325 """ Before cleaning, unmerge stuff """
1327 cmd("/bin/bash "+self.settings["controller_file"]+\
1328 " unmerge "+ myunmerge,"Unmerge script failed.",\
1330 print "unmerge shell script"
1331 except CatalystError:
1334 touch(self.settings["autoresume_path"]+"unmerge")
1336 def target_setup(self):
1337 if "AUTORESUME" in self.settings \
1338 and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
1339 print "Resume point detected, skipping target_setup operation..."
1341 print "Setting up filesystems per filesystem type"
1342 cmd("/bin/bash "+self.settings["controller_file"]+\
1343 " target_image_setup "+ self.settings["target_path"],\
1344 "target_image_setup script failed.",env=self.env)
1345 touch(self.settings["autoresume_path"]+"target_setup")
1347 def setup_overlay(self):
1348 if "AUTORESUME" in self.settings \
1349 and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
1350 print "Resume point detected, skipping setup_overlay operation..."
1352 if self.settings["spec_prefix"]+"/overlay" in self.settings:
1353 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
1354 if os.path.exists(x):
1355 cmd("rsync -a "+x+"/ "+\
1356 self.settings["target_path"],\
1357 self.settings["spec_prefix"]+"overlay: "+x+\
1358 " copy failed.",env=self.env)
1359 touch(self.settings["autoresume_path"]+"setup_overlay")
1361 def create_iso(self):
1362 if "AUTORESUME" in self.settings \
1363 and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
1364 print "Resume point detected, skipping create_iso operation..."
1366 """ Create the ISO """
1367 if "iso" in self.settings:
1368 cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1369 self.settings["iso"],"ISO creation script failed.",\
1371 self.gen_contents_file(self.settings["iso"])
1372 self.gen_digest_file(self.settings["iso"])
1373 touch(self.settings["autoresume_path"]+"create_iso")
1375 print "WARNING: livecd/iso was not defined."
1376 print "An ISO Image will not be created."
1378 def build_packages(self):
1379 if "AUTORESUME" in self.settings \
1380 and os.path.exists(self.settings["autoresume_path"]+\
1382 print "Resume point detected, skipping build_packages operation..."
1384 if self.settings["spec_prefix"]+"/packages" in self.settings:
1385 if "AUTORESUME" in self.settings \
1386 and os.path.exists(self.settings["autoresume_path"]+\
1388 print "Resume point detected, skipping build_packages operation..."
1391 list_bashify(self.settings[self.settings["spec_prefix"]\
1394 cmd("/bin/bash "+self.settings["controller_file"]+\
1395 " build_packages "+mypack,\
1396 "Error in attempt to build packages",env=self.env)
1397 touch(self.settings["autoresume_path"]+"build_packages")
1398 except CatalystError:
1400 raise CatalystError,self.settings["spec_prefix"]+\
1401 "build aborting due to error."
1403 def build_kernel(self):
1404 "Build all configured kernels"
1405 if "AUTORESUME" in self.settings \
1406 and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
1407 print "Resume point detected, skipping build_kernel operation..."
1409 if "boot/kernel" in self.settings:
1411 mynames=self.settings["boot/kernel"]
1412 if type(mynames)==types.StringType:
1415 Execute the script that sets up the kernel build environment
1417 cmd("/bin/bash "+self.settings["controller_file"]+\
1418 " pre-kmerge ","Runscript pre-kmerge failed",\
1420 for kname in mynames:
1421 self._build_kernel(kname=kname)
1422 touch(self.settings["autoresume_path"]+"build_kernel")
1423 except CatalystError:
1425 raise CatalystError,\
1426 "build aborting due to kernel build error."
1428 def _build_kernel(self, kname):
1429 "Build a single configured kernel by name"
1430 if "AUTORESUME" in self.settings \
1431 and os.path.exists(self.settings["autoresume_path"]\
1432 +"build_kernel_"+kname):
1433 print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1435 self._copy_kernel_config(kname=kname)
1438 If we need to pass special options to the bootloader
1439 for this kernel put them into the environment
1441 if "boot/kernel/"+kname+"/kernelopts" in self.settings:
1442 myopts=self.settings["boot/kernel/"+kname+\
1445 if type(myopts) != types.StringType:
1446 myopts = string.join(myopts)
1447 self.env[kname+"_kernelopts"]=myopts
1450 self.env[kname+"_kernelopts"]=""
1452 if "boot/kernel/"+kname+"/extraversion" not in self.settings:
1453 self.settings["boot/kernel/"+kname+\
1456 self.env["clst_kextraversion"]=\
1457 self.settings["boot/kernel/"+kname+\
1460 self._copy_initramfs_overlay(kname=kname)
1462 """ Execute the script that builds the kernel """
1463 cmd("/bin/bash "+self.settings["controller_file"]+\
1465 "Runscript kernel build failed",env=self.env)
1467 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1468 if os.path.exists(self.settings["chroot_path"]+\
1469 "/tmp/initramfs_overlay/"):
1470 print "Cleaning up temporary overlay dir"
1471 cmd("rm -R "+self.settings["chroot_path"]+\
1472 "/tmp/initramfs_overlay/",env=self.env)
1474 touch(self.settings["autoresume_path"]+\
1475 "build_kernel_"+kname)
1478 Execute the script that cleans up the kernel build
1481 cmd("/bin/bash "+self.settings["controller_file"]+\
1483 "Runscript post-kmerge failed",env=self.env)
1485 def _copy_kernel_config(self, kname):
1486 if "boot/kernel/"+kname+"/config" in self.settings:
1487 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1489 raise CatalystError,\
1490 "Can't find kernel config: "+\
1491 self.settings["boot/kernel/"+kname+\
1495 cmd("cp "+self.settings["boot/kernel/"+kname+\
1497 self.settings["chroot_path"]+"/var/tmp/"+\
1499 "Couldn't copy kernel config: "+\
1500 self.settings["boot/kernel/"+kname+\
1501 "/config"],env=self.env)
1503 except CatalystError:
1506 def _copy_initramfs_overlay(self, kname):
1507 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1508 if os.path.exists(self.settings["boot/kernel/"+\
1509 kname+"/initramfs_overlay"]):
1510 print "Copying initramfs_overlay dir "+\
1511 self.settings["boot/kernel/"+kname+\
1512 "/initramfs_overlay"]
1515 self.settings["chroot_path"]+\
1516 "/tmp/initramfs_overlay/"+\
1517 self.settings["boot/kernel/"+kname+\
1518 "/initramfs_overlay"],env=self.env)
1520 cmd("cp -R "+self.settings["boot/kernel/"+\
1521 kname+"/initramfs_overlay"]+"/* "+\
1522 self.settings["chroot_path"]+\
1523 "/tmp/initramfs_overlay/"+\
1524 self.settings["boot/kernel/"+kname+\
1525 "/initramfs_overlay"],env=self.env)
1527 def bootloader(self):
1528 if "AUTORESUME" in self.settings \
1529 and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
1530 print "Resume point detected, skipping bootloader operation..."
1533 cmd("/bin/bash "+self.settings["controller_file"]+\
1534 " bootloader " + self.settings["target_path"],\
1535 "Bootloader script failed.",env=self.env)
1536 touch(self.settings["autoresume_path"]+"bootloader")
1537 except CatalystError:
1539 raise CatalystError,"Script aborting due to error."
1541 def livecd_update(self):
1542 if "AUTORESUME" in self.settings \
1543 and os.path.exists(self.settings["autoresume_path"]+\
1545 print "Resume point detected, skipping build_packages operation..."
1548 cmd("/bin/bash "+self.settings["controller_file"]+\
1549 " livecd-update","livecd-update failed.",env=self.env)
1550 touch(self.settings["autoresume_path"]+"livecd_update")
1552 except CatalystError:
1554 raise CatalystError,"build aborting due to livecd_update error."
1556 def clear_chroot(self):
1557 myemp=self.settings["chroot_path"]
1558 if os.path.isdir(myemp):
1559 print "Emptying directory",myemp
1561 stat the dir, delete the dir, recreate the dir and set
1562 the proper perms and ownership
1564 mystat=os.stat(myemp)
1565 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1566 """ There's no easy way to change flags recursively in python """
1567 if os.uname()[0] == "FreeBSD":
1568 os.system("chflags -R noschg "+myemp)
1569 shutil.rmtree(myemp)
1570 os.makedirs(myemp,0755)
1571 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1572 os.chmod(myemp,mystat[ST_MODE])
1574 def clear_packages(self):
1575 if "PKGCACHE" in self.settings:
1576 print "purging the pkgcache ..."
1578 myemp=self.settings["pkgcache_path"]
1579 if os.path.isdir(myemp):
1580 print "Emptying directory",myemp
1582 stat the dir, delete the dir, recreate the dir and set
1583 the proper perms and ownership
1585 mystat=os.stat(myemp)
1586 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1587 shutil.rmtree(myemp)
1588 os.makedirs(myemp,0755)
1589 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1590 os.chmod(myemp,mystat[ST_MODE])
1592 def clear_kerncache(self):
1593 if "KERNCACHE" in self.settings:
1594 print "purging the kerncache ..."
1596 myemp=self.settings["kerncache_path"]
1597 if os.path.isdir(myemp):
1598 print "Emptying directory",myemp
1600 stat the dir, delete the dir, recreate the dir and set
1601 the proper perms and ownership
1603 mystat=os.stat(myemp)
1604 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1605 shutil.rmtree(myemp)
1606 os.makedirs(myemp,0755)
1607 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1608 os.chmod(myemp,mystat[ST_MODE])
1610 def clear_autoresume(self):
1611 """ Clean resume points since they are no longer needed """
1612 if "AUTORESUME" in self.settings:
1613 print "Removing AutoResume Points: ..."
1614 myemp=self.settings["autoresume_path"]
1615 if os.path.isdir(myemp):
1616 if "AUTORESUME" in self.settings:
1617 print "Emptying directory",myemp
1619 stat the dir, delete the dir, recreate the dir and set
1620 the proper perms and ownership
1622 mystat=os.stat(myemp)
1623 if os.uname()[0] == "FreeBSD":
1624 cmd("chflags -R noschg "+myemp,\
1625 "Could not remove immutable flag for file "\
1627 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1628 shutil.rmtree(myemp)
1629 os.makedirs(myemp,0755)
1630 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1631 os.chmod(myemp,mystat[ST_MODE])
1633 def gen_contents_file(self,file):
1634 if os.path.exists(file+".CONTENTS"):
1635 os.remove(file+".CONTENTS")
1636 if "contents" in self.settings:
1637 if os.path.exists(file):
1638 myf=open(file+".CONTENTS","w")
1640 for i in self.settings["contents"].split():
1645 contents=generate_contents(file,contents_function=j,\
1646 verbose="VERBOSE" in self.settings)
1651 def gen_digest_file(self,file):
1652 if os.path.exists(file+".DIGESTS"):
1653 os.remove(file+".DIGESTS")
1654 if "digests" in self.settings:
1655 if os.path.exists(file):
1656 myf=open(file+".DIGESTS","w")
1658 for i in self.settings["digests"].split():
1662 for f in [file, file+'.CONTENTS']:
1663 if os.path.exists(f):
1665 for k in hash_map.keys():
1666 hash=generate_hash(f,hash_function=k,verbose=\
1667 "VERBOSE" in self.settings)
1671 hash=generate_hash(f,hash_function=j,verbose=\
1672 "VERBOSE" in self.settings)
1677 countdown(10,"Purging Caches ...")
1678 if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
1679 print "clearing autoresume ..."
1680 self.clear_autoresume()
1682 print "clearing chroot ..."
1685 if "PURGETMPONLY" not in self.settings:
1686 print "clearing package cache ..."
1687 self.clear_packages()
1689 print "clearing kerncache ..."
1690 self.clear_kerncache()
1692 # vim: ts=4 sw=4 sta et sts=4 ai