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/*", self.settings["portdir"]]
411 def set_snapshot_path(self):
412 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
413 "/snapshots/" + self.settings["snapshot_name"] +
414 self.settings["snapshot"] + ".tar.xz")
416 if os.path.exists(self.settings["snapshot_path"]):
417 self.settings["snapshot_path_hash"]=\
418 generate_hash(self.settings["snapshot_path"],\
419 hash_function=self.settings["hash_function"],verbose=False)
421 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
422 "/snapshots/" + self.settings["snapshot_name"] +
423 self.settings["snapshot"] + ".tar.bz2")
425 if os.path.exists(self.settings["snapshot_path"]):
426 self.settings["snapshot_path_hash"]=\
427 generate_hash(self.settings["snapshot_path"],\
428 hash_function=self.settings["hash_function"],verbose=False)
430 def set_snapcache_path(self):
431 if "SNAPCACHE" in self.settings:
432 self.settings["snapshot_cache_path"]=\
433 normpath(self.settings["snapshot_cache"]+"/"+\
434 self.settings["snapshot"]+"/")
435 self.snapcache_lock=\
436 catalyst_lock.LockDir(self.settings["snapshot_cache_path"])
437 print "Caching snapshot to "+self.settings["snapshot_cache_path"]
439 def set_chroot_path(self):
441 NOTE: the trailing slash is very important!
442 Things *will* break without it!
444 self.settings["chroot_path"]=normpath(self.settings["storedir"]+\
445 "/tmp/"+self.settings["target_subpath"]+"/")
446 self.chroot_lock=catalyst_lock.LockDir(self.settings["chroot_path"])
448 def set_autoresume_path(self):
449 self.settings["autoresume_path"]=normpath(self.settings["storedir"]+\
450 "/tmp/"+self.settings["rel_type"]+"/"+".autoresume-"+\
451 self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
452 self.settings["version_stamp"]+"/")
453 if "AUTORESUME" in self.settings:
454 print "The autoresume path is " + self.settings["autoresume_path"]
455 if not os.path.exists(self.settings["autoresume_path"]):
456 os.makedirs(self.settings["autoresume_path"],0755)
458 def set_controller_file(self):
459 self.settings["controller_file"]=normpath(self.settings["sharedir"]+\
460 "/targets/"+self.settings["target"]+"/"+self.settings["target"]+\
463 def set_iso_volume_id(self):
464 if self.settings["spec_prefix"]+"/volid" in self.settings:
465 self.settings["iso_volume_id"]=\
466 self.settings[self.settings["spec_prefix"]+"/volid"]
467 if len(self.settings["iso_volume_id"])>32:
468 raise CatalystError,\
469 "ISO volume ID must not exceed 32 characters."
471 self.settings["iso_volume_id"]="catalyst "+self.settings["snapshot"]
473 def set_action_sequence(self):
474 """ Default action sequence for run method """
475 self.settings["action_sequence"]=["unpack","unpack_snapshot",\
476 "setup_confdir","portage_overlay",\
477 "base_dirs","bind","chroot_setup","setup_environment",\
478 "run_local","preclean","unbind","clean"]
479 # if "TARBALL" in self.settings or \
480 # "FETCH" not in self.settings:
481 if "FETCH" not in self.settings:
482 self.settings["action_sequence"].append("capture")
483 self.settings["action_sequence"].append("clear_autoresume")
486 if self.settings["spec_prefix"]+"/use" in self.settings:
487 self.settings["use"]=\
488 self.settings[self.settings["spec_prefix"]+"/use"]
489 del self.settings[self.settings["spec_prefix"]+"/use"]
490 if "use" not in self.settings:
491 self.settings["use"]=""
492 if type(self.settings["use"])==types.StringType:
493 self.settings["use"]=self.settings["use"].split()
495 # Force bindist when options ask for it
496 if "BINDIST" in self.settings:
497 self.settings["use"].append("bindist")
499 def set_stage_path(self):
500 self.settings["stage_path"]=normpath(self.settings["chroot_path"])
502 def set_mounts(self):
505 def set_packages(self):
509 if self.settings["spec_prefix"]+"/rm" in self.settings:
510 if type(self.settings[self.settings["spec_prefix"]+\
511 "/rm"])==types.StringType:
512 self.settings[self.settings["spec_prefix"]+"/rm"]=\
513 self.settings[self.settings["spec_prefix"]+"/rm"].split()
515 def set_linuxrc(self):
516 if self.settings["spec_prefix"]+"/linuxrc" in self.settings:
517 if type(self.settings[self.settings["spec_prefix"]+\
518 "/linuxrc"])==types.StringType:
519 self.settings["linuxrc"]=\
520 self.settings[self.settings["spec_prefix"]+"/linuxrc"]
521 del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
523 def set_busybox_config(self):
524 if self.settings["spec_prefix"]+"/busybox_config" in self.settings:
525 if type(self.settings[self.settings["spec_prefix"]+\
526 "/busybox_config"])==types.StringType:
527 self.settings["busybox_config"]=\
528 self.settings[self.settings["spec_prefix"]+"/busybox_config"]
529 del self.settings[self.settings["spec_prefix"]+"/busybox_config"]
531 def set_portage_overlay(self):
532 if "portage_overlay" in self.settings:
533 if type(self.settings["portage_overlay"])==types.StringType:
534 self.settings["portage_overlay"]=\
535 self.settings["portage_overlay"].split()
536 print "portage_overlay directories are set to: \""+\
537 string.join(self.settings["portage_overlay"])+"\""
539 def set_overlay(self):
540 if self.settings["spec_prefix"]+"/overlay" in self.settings:
541 if type(self.settings[self.settings["spec_prefix"]+\
542 "/overlay"])==types.StringType:
543 self.settings[self.settings["spec_prefix"]+"/overlay"]=\
544 self.settings[self.settings["spec_prefix"]+\
547 def set_root_overlay(self):
548 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
549 if type(self.settings[self.settings["spec_prefix"]+\
550 "/root_overlay"])==types.StringType:
551 self.settings[self.settings["spec_prefix"]+"/root_overlay"]=\
552 self.settings[self.settings["spec_prefix"]+\
553 "/root_overlay"].split()
555 def set_root_path(self):
556 """ ROOT= variable for emerges """
557 self.settings["root_path"]="/"
559 def set_valid_build_kernel_vars(self,addlargs):
560 if "boot/kernel" in addlargs:
561 if type(addlargs["boot/kernel"])==types.StringType:
562 loopy=[addlargs["boot/kernel"]]
564 loopy=addlargs["boot/kernel"]
567 self.valid_values.append("boot/kernel/"+x+"/aliases")
568 self.valid_values.append("boot/kernel/"+x+"/config")
569 self.valid_values.append("boot/kernel/"+x+"/console")
570 self.valid_values.append("boot/kernel/"+x+"/extraversion")
571 self.valid_values.append("boot/kernel/"+x+"/gk_action")
572 self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
573 self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
574 self.valid_values.append("boot/kernel/"+x+"/machine_type")
575 self.valid_values.append("boot/kernel/"+x+"/sources")
576 self.valid_values.append("boot/kernel/"+x+"/softlevel")
577 self.valid_values.append("boot/kernel/"+x+"/use")
578 self.valid_values.append("boot/kernel/"+x+"/packages")
579 if "boot/kernel/"+x+"/packages" in addlargs:
580 if type(addlargs["boot/kernel/"+x+\
581 "/packages"])==types.StringType:
582 addlargs["boot/kernel/"+x+"/packages"]=\
583 [addlargs["boot/kernel/"+x+"/packages"]]
585 def set_build_kernel_vars(self):
586 if self.settings["spec_prefix"]+"/gk_mainargs" in self.settings:
587 self.settings["gk_mainargs"]=\
588 self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
589 del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
591 def kill_chroot_pids(self):
592 print "Checking for processes running in chroot and killing them."
595 Force environment variables to be exported so script can see them
597 self.setup_environment()
599 if os.path.exists(self.settings["sharedir"]+\
600 "/targets/support/kill-chroot-pids.sh"):
601 cmd("/bin/bash "+self.settings["sharedir"]+\
602 "/targets/support/kill-chroot-pids.sh",\
603 "kill-chroot-pids script failed.",env=self.env)
605 def mount_safety_check(self):
606 mypath=self.settings["chroot_path"]
609 Check and verify that none of our paths in mypath are mounted. We don't
610 want to clean up with things still mounted, and this allows us to check.
611 Returns 1 on ok, 0 on "something is still mounted" case.
614 if not os.path.exists(mypath):
617 for x in self.mounts:
618 if not os.path.exists(mypath + self.mountmap[x]):
621 if ismount(mypath + self.mountmap[x]):
622 """ Something is still mounted "" """
624 print self.mountmap[x] + " is still mounted; performing auto-bind-umount...",
625 """ Try to umount stuff ourselves """
627 if ismount(mypath + self.mountmap[x]):
628 raise CatalystError, "Auto-unbind failed for " + self.mountmap[x]
630 print "Auto-unbind successful..."
631 except CatalystError:
632 raise CatalystError, "Unable to auto-unbind " + self.mountmap[x]
637 clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+\
640 if "SEEDCACHE" in self.settings:
641 if os.path.isdir(self.settings["source_path"]):
642 """ SEEDCACHE Is a directory, use rsync """
643 unpack_cmd="rsync -a --delete "+self.settings["source_path"]+\
644 " "+self.settings["chroot_path"]
645 display_msg="\nStarting rsync from "+\
646 self.settings["source_path"]+"\nto "+\
647 self.settings["chroot_path"]+\
648 " (This may take some time) ...\n"
649 error_msg="Rsync of "+self.settings["source_path"]+" to "+\
650 self.settings["chroot_path"]+" failed."
652 """ SEEDCACHE is a not a directory, try untar'ing """
653 print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
654 display_msg="\nStarting tar extract from "+\
655 self.settings["source_path"]+"\nto "+\
656 self.settings["chroot_path"]+\
657 " (This may take some time) ...\n"
658 if "bz2" == self.settings["chroot_path"][-3:]:
659 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
660 self.settings["chroot_path"]
662 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
663 self.settings["chroot_path"]
664 error_msg="Tarball extraction of "+\
665 self.settings["source_path"]+" to "+\
666 self.settings["chroot_path"]+" failed."
668 """ No SEEDCACHE, use tar """
669 display_msg="\nStarting tar extract from "+\
670 self.settings["source_path"]+"\nto "+\
671 self.settings["chroot_path"]+\
672 " (This may take some time) ...\n"
673 if "bz2" == self.settings["chroot_path"][-3:]:
674 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
675 self.settings["chroot_path"]
677 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
678 self.settings["chroot_path"]
679 error_msg="Tarball extraction of "+self.settings["source_path"]+\
680 " to "+self.settings["chroot_path"]+" failed."
682 if "AUTORESUME" in self.settings:
683 if os.path.isdir(self.settings["source_path"]) \
684 and os.path.exists(self.settings["autoresume_path"]+"unpack"):
685 """ Autoresume is valid, SEEDCACHE is valid """
687 invalid_snapshot=False
689 elif os.path.isfile(self.settings["source_path"]) \
690 and self.settings["source_path_hash"]==clst_unpack_hash:
691 """ Autoresume is valid, tarball is valid """
693 invalid_snapshot=True
695 elif os.path.isdir(self.settings["source_path"]) \
696 and not os.path.exists(self.settings["autoresume_path"]+\
698 """ Autoresume is invalid, SEEDCACHE """
700 invalid_snapshot=False
702 elif os.path.isfile(self.settings["source_path"]) \
703 and self.settings["source_path_hash"]!=clst_unpack_hash:
704 """ Autoresume is invalid, tarball """
706 invalid_snapshot=True
708 """ No autoresume, SEEDCACHE """
709 if "SEEDCACHE" in self.settings:
710 """ SEEDCACHE so let's run rsync and let it clean up """
711 if os.path.isdir(self.settings["source_path"]):
713 invalid_snapshot=False
714 elif os.path.isfile(self.settings["source_path"]):
715 """ Tarball so unpack and remove anything already there """
717 invalid_snapshot=True
718 """ No autoresume, no SEEDCACHE """
720 """ Tarball so unpack and remove anything already there """
721 if os.path.isfile(self.settings["source_path"]):
723 invalid_snapshot=True
724 elif os.path.isdir(self.settings["source_path"]):
725 """ We should never reach this, so something is very wrong """
726 raise CatalystError,\
727 "source path is a dir but seedcache is not enabled"
730 self.mount_safety_check()
733 if "AUTORESUME" in self.settings:
734 print "No Valid Resume point detected, cleaning up..."
736 self.clear_autoresume()
739 if not os.path.exists(self.settings["chroot_path"]):
740 os.makedirs(self.settings["chroot_path"])
742 if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
743 os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
745 if "PKGCACHE" in self.settings:
746 if not os.path.exists(self.settings["pkgcache_path"]):
747 os.makedirs(self.settings["pkgcache_path"],0755)
749 if "KERNCACHE" in self.settings:
750 if not os.path.exists(self.settings["kerncache_path"]):
751 os.makedirs(self.settings["kerncache_path"],0755)
754 cmd(unpack_cmd,error_msg,env=self.env)
756 if "source_path_hash" in self.settings:
757 myf=open(self.settings["autoresume_path"]+"unpack","w")
758 myf.write(self.settings["source_path_hash"])
761 touch(self.settings["autoresume_path"]+"unpack")
763 print "Resume point detected, skipping unpack operation..."
765 def unpack_snapshot(self):
767 snapshot_hash=read_from_clst(self.settings["autoresume_path"]+\
770 if "SNAPCACHE" in self.settings:
771 snapshot_cache_hash=\
772 read_from_clst(self.settings["snapshot_cache_path"]+\
774 destdir=self.settings["snapshot_cache_path"]
775 if "bz2" == self.settings["chroot_path"][-3:]:
776 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+destdir
778 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+destdir
779 unpack_errmsg="Error unpacking snapshot"
780 cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+\
781 self.settings["snapshot_cache_path"]+\
782 " (This can take a long time)..."
783 cleanup_errmsg="Error removing existing snapshot cache directory."
784 self.snapshot_lock_object=self.snapcache_lock
786 if self.settings["snapshot_path_hash"]==snapshot_cache_hash:
787 print "Valid snapshot cache, skipping unpack of portage tree..."
790 destdir = normpath(self.settings["chroot_path"] + self.settings["portdir"])
791 cleanup_errmsg="Error removing existing snapshot directory."
793 "Cleaning up existing portage tree (This can take a long time)..."
794 if "bz2" == self.settings["chroot_path"][-3:]:
795 unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+\
796 self.settings["chroot_path"]+"/usr"
798 unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+\
799 self.settings["chroot_path"]+"/usr"
800 unpack_errmsg="Error unpacking snapshot"
802 if "AUTORESUME" in self.settings \
803 and os.path.exists(self.settings["chroot_path"]+\
804 self.settings["portdir"]) \
805 and os.path.exists(self.settings["autoresume_path"]\
807 and self.settings["snapshot_path_hash"] == snapshot_hash:
809 "Valid Resume point detected, skipping unpack of portage tree..."
813 if "SNAPCACHE" in self.settings:
814 self.snapshot_lock_object.write_lock()
815 if os.path.exists(destdir):
817 cleanup_cmd="rm -rf "+destdir
818 cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
819 if not os.path.exists(destdir):
820 os.makedirs(destdir,0755)
822 print "Unpacking portage tree (This can take a long time) ..."
823 cmd(unpack_cmd,unpack_errmsg,env=self.env)
825 if "SNAPCACHE" in self.settings:
826 myf=open(self.settings["snapshot_cache_path"]+"catalyst-hash","w")
827 myf.write(self.settings["snapshot_path_hash"])
830 print "Setting snapshot autoresume point"
831 myf=open(self.settings["autoresume_path"]+"unpack_portage","w")
832 myf.write(self.settings["snapshot_path_hash"])
835 if "SNAPCACHE" in self.settings:
836 self.snapshot_lock_object.unlock()
838 def config_profile_link(self):
839 if "AUTORESUME" in self.settings \
840 and os.path.exists(self.settings["autoresume_path"]+\
841 "config_profile_link"):
843 "Resume point detected, skipping config_profile_link operation..."
845 # TODO: zmedico and I discussed making this a directory and pushing
846 # in a parent file, as well as other user-specified configuration.
847 print "Configuring profile link..."
848 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.profile",\
849 "Error zapping profile link",env=self.env)
850 cmd("mkdir -p "+self.settings["chroot_path"]+"/etc/portage/")
851 cmd("ln -sf ../.." + self.settings["portdir"] + "/profiles/" + \
852 self.settings["target_profile"]+" "+\
853 self.settings["chroot_path"]+"/etc/portage/make.profile",\
854 "Error creating profile link",env=self.env)
855 touch(self.settings["autoresume_path"]+"config_profile_link")
857 def setup_confdir(self):
858 if "AUTORESUME" in self.settings \
859 and os.path.exists(self.settings["autoresume_path"]+\
861 print "Resume point detected, skipping setup_confdir operation..."
863 if "portage_confdir" in self.settings:
864 print "Configuring /etc/portage..."
865 cmd("rsync -a "+self.settings["portage_confdir"]+"/ "+\
866 self.settings["chroot_path"]+"/etc/portage/",\
867 "Error copying /etc/portage",env=self.env)
868 touch(self.settings["autoresume_path"]+"setup_confdir")
870 def portage_overlay(self):
871 """ We copy the contents of our overlays to /usr/local/portage """
872 if "portage_overlay" in self.settings:
873 for x in self.settings["portage_overlay"]:
874 if os.path.exists(x):
875 print "Copying overlay dir " +x
876 cmd("mkdir -p "+self.settings["chroot_path"]+\
877 self.settings["local_overlay"],\
878 "Could not make portage_overlay dir",env=self.env)
879 cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+\
880 self.settings["local_overlay"],\
881 "Could not copy portage_overlay",env=self.env)
883 def root_overlay(self):
884 """ Copy over the root_overlay """
885 if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
886 for x in self.settings[self.settings["spec_prefix"]+\
888 if os.path.exists(x):
889 print "Copying root_overlay: "+x
890 cmd("rsync -a "+x+"/ "+\
891 self.settings["chroot_path"],\
892 self.settings["spec_prefix"]+"/root_overlay: "+x+\
893 " copy failed.",env=self.env)
899 for x in self.mounts:
900 if not os.path.exists(self.settings["chroot_path"] + self.mountmap[x]):
901 os.makedirs(self.settings["chroot_path"]+x,0755)
903 if not os.path.exists(self.mountmap[x]):
904 if not self.mountmap[x] == "tmpfs":
905 os.makedirs(self.mountmap[x],0755)
908 if "SNAPCACHE" in self.settings and x == "/usr/portage":
909 self.snapshot_lock_object.read_lock()
910 if os.uname()[0] == "FreeBSD":
912 retval = os.system("mount -t devfs none " +
913 self.settings["chroot_path"] + src)
915 retval = os.system("mount_nullfs " + src + " " +
916 self.settings["chroot_path"] + src)
919 if "var_tmpfs_portage" in self.settings:
920 retval=os.system("mount -t tmpfs -o size="+\
921 self.settings["var_tmpfs_portage"]+"G "+src+" "+\
922 self.settings["chroot_path"]+x)
924 retval = os.system("mount --bind " + src + " " +
925 self.settings["chroot_path"] + src)
928 raise CatalystError,"Couldn't bind mount " + src
932 mypath=self.settings["chroot_path"]
933 myrevmounts=self.mounts[:]
934 myrevmounts.reverse()
935 """ Unmount in reverse order for nested bind-mounts """
936 for x in myrevmounts:
937 if not os.path.exists(mypath + self.mountmap[x]):
940 if not ismount(mypath + self.mountmap[x]):
943 retval=os.system("umount "+\
944 os.path.join(mypath, self.mountmap[x].lstrip(os.path.sep)))
947 warn("First attempt to unmount: " + mypath +
948 self.mountmap[x] +" failed.")
949 warn("Killing any pids still running in the chroot")
951 self.kill_chroot_pids()
953 retval2 = os.system("umount " + mypath + self.mountmap[x])
956 warn("Couldn't umount bind mount: " + mypath + self.mountmap[x])
958 if "SNAPCACHE" in self.settings and x == "/usr/portage":
961 It's possible the snapshot lock object isn't created yet.
962 This is because mount safety check calls unbind before the
963 target is fully initialized
965 self.snapshot_lock_object.unlock()
970 if any bind mounts really failed, then we need to raise
971 this to potentially prevent an upcoming bash stage cleanup script
972 from wiping our bind mounts.
974 raise CatalystError,\
975 "Couldn't umount one or more bind-mounts; aborting for safety."
977 def chroot_setup(self):
978 self.makeconf=read_makeconf(self.settings["chroot_path"]+\
979 "/etc/portage/make.conf")
980 self.override_cbuild()
981 self.override_chost()
982 self.override_cflags()
983 self.override_cxxflags()
984 self.override_ldflags()
985 if "AUTORESUME" in self.settings \
986 and os.path.exists(self.settings["autoresume_path"]+"chroot_setup"):
987 print "Resume point detected, skipping chroot_setup operation..."
989 print "Setting up chroot..."
991 #self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/portage/make.conf")
993 cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
994 "Could not copy resolv.conf into place.",env=self.env)
996 """ Copy over the envscript, if applicable """
997 if "ENVSCRIPT" in self.settings:
998 if not os.path.exists(self.settings["ENVSCRIPT"]):
999 raise CatalystError,\
1000 "Can't find envscript "+self.settings["ENVSCRIPT"]
1002 print "\nWarning!!!!"
1003 print "\tOverriding certain env variables may cause catastrophic failure."
1004 print "\tIf your build fails look here first as the possible problem."
1005 print "\tCatalyst assumes you know what you are doing when setting"
1006 print "\t\tthese variables."
1007 print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
1008 print "\tYou have been warned\n"
1010 cmd("cp "+self.settings["ENVSCRIPT"]+" "+\
1011 self.settings["chroot_path"]+"/tmp/envscript",\
1012 "Could not copy envscript into place.",env=self.env)
1015 Copy over /etc/hosts from the host in case there are any
1016 specialties in there
1018 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
1019 cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+\
1020 self.settings["chroot_path"]+"/etc/hosts.catalyst",\
1021 "Could not backup /etc/hosts",env=self.env)
1022 cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts",\
1023 "Could not copy /etc/hosts",env=self.env)
1025 """ Modify and write out make.conf (for the chroot) """
1026 cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.conf",\
1027 "Could not remove "+self.settings["chroot_path"]+\
1028 "/etc/portage/make.conf",env=self.env)
1029 myf=open(self.settings["chroot_path"]+"/etc/portage/make.conf","w")
1030 myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
1031 myf.write("# Please consult /usr/share/portage/config/make.conf.example for a more\n# detailed example.\n")
1032 if "CFLAGS" in self.settings:
1033 myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
1034 if "CXXFLAGS" in self.settings:
1035 if self.settings["CXXFLAGS"]!=self.settings["CFLAGS"]:
1036 myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
1038 myf.write('CXXFLAGS="${CFLAGS}"\n')
1040 myf.write('CXXFLAGS="${CFLAGS}"\n')
1042 if "LDFLAGS" in self.settings:
1043 myf.write("# LDFLAGS is unsupported. USE AT YOUR OWN RISK!\n")
1044 myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
1045 if "CBUILD" in self.settings:
1046 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")
1047 myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
1049 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")
1050 myf.write('CHOST="'+self.settings["CHOST"]+'"\n')
1052 """ Figure out what our USE vars are for building """
1054 if "HOSTUSE" in self.settings:
1055 myusevars.extend(self.settings["HOSTUSE"])
1057 if "use" in self.settings:
1058 myusevars.extend(self.settings["use"])
1061 myf.write("# These are the USE flags that were used in addition to what is provided by the\n# profile used for building.\n")
1062 myusevars = sorted(set(myusevars))
1063 myf.write('USE="'+string.join(myusevars)+'"\n')
1064 if '-*' in myusevars:
1065 print "\nWarning!!! "
1066 print "\tThe use of -* in "+self.settings["spec_prefix"]+\
1067 "/use will cause portage to ignore"
1068 print "\tpackage.use in the profile and portage_confdir. You've been warned!"
1070 myf.write('PORTDIR="%s"\n' % self.settings['portdir'])
1071 myf.write('DISTDIR="%s"\n' % self.settings['distdir'])
1072 myf.write('PKGDIR="%s"\n' % self.settings['packagedir'])
1074 """ Setup the portage overlay """
1075 if "portage_overlay" in self.settings:
1076 myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
1079 cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
1080 self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
1081 "Could not backup /etc/portage/make.conf",env=self.env)
1082 touch(self.settings["autoresume_path"]+"chroot_setup")
1085 if "AUTORESUME" in self.settings \
1086 and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
1087 print "Resume point detected, skipping fsscript operation..."
1089 if "fsscript" in self.settings:
1090 if os.path.exists(self.settings["controller_file"]):
1091 cmd("/bin/bash "+self.settings["controller_file"]+\
1092 " fsscript","fsscript script failed.",env=self.env)
1093 touch(self.settings["autoresume_path"]+"fsscript")
1096 if "AUTORESUME" in self.settings \
1097 and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
1098 print "Resume point detected, skipping rcupdate operation..."
1100 if os.path.exists(self.settings["controller_file"]):
1101 cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
1102 "rc-update script failed.",env=self.env)
1103 touch(self.settings["autoresume_path"]+"rcupdate")
1106 if "AUTORESUME" in self.settings \
1107 and os.path.exists(self.settings["autoresume_path"]+"clean"):
1108 print "Resume point detected, skipping clean operation..."
1110 for x in self.settings["cleanables"]:
1111 print "Cleaning chroot: "+x+"... "
1112 cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
1115 """ Put /etc/hosts back into place """
1116 if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
1117 cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
1118 self.settings["chroot_path"]+"/etc/hosts",\
1119 "Could not replace /etc/hosts",env=self.env)
1121 """ Remove our overlay """
1122 if os.path.exists(self.settings["chroot_path"] + self.settings["local_overlay"]):
1123 cmd("rm -rf " + self.settings["chroot_path"] + self.settings["local_overlay"],
1124 "Could not remove " + self.settings["local_overlay"], env=self.env)
1125 cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
1126 "/etc/portage/make.conf",\
1127 "Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
1129 """ Clean up old and obsoleted files in /etc """
1130 if os.path.exists(self.settings["stage_path"]+"/etc"):
1131 cmd("find "+self.settings["stage_path"]+\
1132 "/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
1133 "Could not remove stray files in /etc",env=self.env)
1135 if os.path.exists(self.settings["controller_file"]):
1136 cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
1137 "clean script failed.",env=self.env)
1138 touch(self.settings["autoresume_path"]+"clean")
1141 if "AUTORESUME" in self.settings \
1142 and os.path.exists(self.settings["autoresume_path"]+"empty"):
1143 print "Resume point detected, skipping empty operation..."
1145 if self.settings["spec_prefix"]+"/empty" in self.settings:
1146 if type(self.settings[self.settings["spec_prefix"]+\
1147 "/empty"])==types.StringType:
1148 self.settings[self.settings["spec_prefix"]+"/empty"]=\
1149 self.settings[self.settings["spec_prefix"]+\
1151 for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
1152 myemp=self.settings["destpath"]+x
1153 if not os.path.isdir(myemp) or os.path.islink(myemp):
1154 print x,"not a directory or does not exist, skipping 'empty' operation."
1156 print "Emptying directory",x
1158 stat the dir, delete the dir, recreate the dir and set
1159 the proper perms and ownership
1161 mystat=os.stat(myemp)
1162 shutil.rmtree(myemp)
1163 os.makedirs(myemp,0755)
1164 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1165 os.chmod(myemp,mystat[ST_MODE])
1166 touch(self.settings["autoresume_path"]+"empty")
1169 if "AUTORESUME" in self.settings \
1170 and os.path.exists(self.settings["autoresume_path"]+"remove"):
1171 print "Resume point detected, skipping remove operation..."
1173 if self.settings["spec_prefix"]+"/rm" in self.settings:
1174 for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
1176 We're going to shell out for all these cleaning
1177 operations, so we get easy glob handling.
1179 print "livecd: removing "+x
1180 os.system("rm -rf "+self.settings["chroot_path"]+x)
1182 if os.path.exists(self.settings["controller_file"]):
1183 cmd("/bin/bash "+self.settings["controller_file"]+\
1184 " clean","Clean failed.",env=self.env)
1185 touch(self.settings["autoresume_path"]+"remove")
1191 if "AUTORESUME" in self.settings \
1192 and os.path.exists(self.settings["autoresume_path"]+"preclean"):
1193 print "Resume point detected, skipping preclean operation..."
1196 if os.path.exists(self.settings["controller_file"]):
1197 cmd("/bin/bash "+self.settings["controller_file"]+\
1198 " preclean","preclean script failed.",env=self.env)
1199 touch(self.settings["autoresume_path"]+"preclean")
1203 raise CatalystError, "Build failed, could not execute preclean"
1206 if "AUTORESUME" in self.settings \
1207 and os.path.exists(self.settings["autoresume_path"]+"capture"):
1208 print "Resume point detected, skipping capture operation..."
1210 """ Capture target in a tarball """
1211 mypath=self.settings["target_path"].split("/")
1212 """ Remove filename from path """
1213 mypath=string.join(mypath[:-1],"/")
1215 """ Now make sure path exists """
1216 if not os.path.exists(mypath):
1219 print "Creating stage tarball..."
1221 cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
1222 self.settings["stage_path"]+" .",\
1223 "Couldn't create stage tarball",env=self.env)
1225 self.gen_contents_file(self.settings["target_path"])
1226 self.gen_digest_file(self.settings["target_path"])
1228 touch(self.settings["autoresume_path"]+"capture")
1230 def run_local(self):
1231 if "AUTORESUME" in self.settings \
1232 and os.path.exists(self.settings["autoresume_path"]+"run_local"):
1233 print "Resume point detected, skipping run_local operation..."
1236 if os.path.exists(self.settings["controller_file"]):
1237 cmd("/bin/bash "+self.settings["controller_file"]+" run",\
1238 "run script failed.",env=self.env)
1239 touch(self.settings["autoresume_path"]+"run_local")
1241 except CatalystError:
1243 raise CatalystError,"Stage build aborting due to error."
1245 def setup_environment(self):
1247 Modify the current environment. This is an ugly hack that should be
1248 fixed. We need this to use the os.system() call since we can't
1249 specify our own environ
1251 for x in self.settings.keys():
1252 """ Sanitize var names by doing "s|/-.|_|g" """
1253 varname="clst_"+string.replace(x,"/","_")
1254 varname=string.replace(varname,"-","_")
1255 varname=string.replace(varname,".","_")
1256 if type(self.settings[x])==types.StringType:
1257 """ Prefix to prevent namespace clashes """
1258 #os.environ[varname]=self.settings[x]
1259 self.env[varname]=self.settings[x]
1260 elif type(self.settings[x])==types.ListType:
1261 #os.environ[varname]=string.join(self.settings[x])
1262 self.env[varname]=string.join(self.settings[x])
1263 elif type(self.settings[x])==types.BooleanType:
1264 if self.settings[x]:
1265 self.env[varname]="true"
1267 self.env[varname]="false"
1268 if "makeopts" in self.settings:
1269 self.env["MAKEOPTS"]=self.settings["makeopts"]
1272 self.chroot_lock.write_lock()
1274 """ Kill any pids in the chroot "" """
1275 self.kill_chroot_pids()
1277 """ Check for mounts right away and abort if we cannot unmount them """
1278 self.mount_safety_check()
1280 if "CLEAR_AUTORESUME" in self.settings:
1281 self.clear_autoresume()
1283 if "PURGETMPONLY" in self.settings:
1287 if "PURGEONLY" in self.settings:
1291 if "PURGE" in self.settings:
1294 for x in self.settings["action_sequence"]:
1295 print "--- Running action sequence: "+x
1298 apply(getattr(self,x))
1300 self.mount_safety_check()
1303 self.chroot_lock.unlock()
1306 if "AUTORESUME" in self.settings \
1307 and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
1308 print "Resume point detected, skipping unmerge operation..."
1310 if self.settings["spec_prefix"]+"/unmerge" in self.settings:
1311 if type(self.settings[self.settings["spec_prefix"]+\
1312 "/unmerge"])==types.StringType:
1313 self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
1314 [self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1316 self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1318 for x in range(0,len(myunmerge)):
1320 Surround args with quotes for passing to bash, allows
1321 things like "<" to remain intact
1323 myunmerge[x]="'"+myunmerge[x]+"'"
1324 myunmerge=string.join(myunmerge)
1326 """ Before cleaning, unmerge stuff """
1328 cmd("/bin/bash "+self.settings["controller_file"]+\
1329 " unmerge "+ myunmerge,"Unmerge script failed.",\
1331 print "unmerge shell script"
1332 except CatalystError:
1335 touch(self.settings["autoresume_path"]+"unmerge")
1337 def target_setup(self):
1338 if "AUTORESUME" in self.settings \
1339 and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
1340 print "Resume point detected, skipping target_setup operation..."
1342 print "Setting up filesystems per filesystem type"
1343 cmd("/bin/bash "+self.settings["controller_file"]+\
1344 " target_image_setup "+ self.settings["target_path"],\
1345 "target_image_setup script failed.",env=self.env)
1346 touch(self.settings["autoresume_path"]+"target_setup")
1348 def setup_overlay(self):
1349 if "AUTORESUME" in self.settings \
1350 and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
1351 print "Resume point detected, skipping setup_overlay operation..."
1353 if self.settings["spec_prefix"]+"/overlay" in self.settings:
1354 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
1355 if os.path.exists(x):
1356 cmd("rsync -a "+x+"/ "+\
1357 self.settings["target_path"],\
1358 self.settings["spec_prefix"]+"overlay: "+x+\
1359 " copy failed.",env=self.env)
1360 touch(self.settings["autoresume_path"]+"setup_overlay")
1362 def create_iso(self):
1363 if "AUTORESUME" in self.settings \
1364 and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
1365 print "Resume point detected, skipping create_iso operation..."
1367 """ Create the ISO """
1368 if "iso" in self.settings:
1369 cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1370 self.settings["iso"],"ISO creation script failed.",\
1372 self.gen_contents_file(self.settings["iso"])
1373 self.gen_digest_file(self.settings["iso"])
1374 touch(self.settings["autoresume_path"]+"create_iso")
1376 print "WARNING: livecd/iso was not defined."
1377 print "An ISO Image will not be created."
1379 def build_packages(self):
1380 if "AUTORESUME" in self.settings \
1381 and os.path.exists(self.settings["autoresume_path"]+\
1383 print "Resume point detected, skipping build_packages operation..."
1385 if self.settings["spec_prefix"]+"/packages" in self.settings:
1386 if "AUTORESUME" in self.settings \
1387 and os.path.exists(self.settings["autoresume_path"]+\
1389 print "Resume point detected, skipping build_packages operation..."
1392 list_bashify(self.settings[self.settings["spec_prefix"]\
1395 cmd("/bin/bash "+self.settings["controller_file"]+\
1396 " build_packages "+mypack,\
1397 "Error in attempt to build packages",env=self.env)
1398 touch(self.settings["autoresume_path"]+"build_packages")
1399 except CatalystError:
1401 raise CatalystError,self.settings["spec_prefix"]+\
1402 "build aborting due to error."
1404 def build_kernel(self):
1405 "Build all configured kernels"
1406 if "AUTORESUME" in self.settings \
1407 and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
1408 print "Resume point detected, skipping build_kernel operation..."
1410 if "boot/kernel" in self.settings:
1412 mynames=self.settings["boot/kernel"]
1413 if type(mynames)==types.StringType:
1416 Execute the script that sets up the kernel build environment
1418 cmd("/bin/bash "+self.settings["controller_file"]+\
1419 " pre-kmerge ","Runscript pre-kmerge failed",\
1421 for kname in mynames:
1422 self._build_kernel(kname=kname)
1423 touch(self.settings["autoresume_path"]+"build_kernel")
1424 except CatalystError:
1426 raise CatalystError,\
1427 "build aborting due to kernel build error."
1429 def _build_kernel(self, kname):
1430 "Build a single configured kernel by name"
1431 if "AUTORESUME" in self.settings \
1432 and os.path.exists(self.settings["autoresume_path"]\
1433 +"build_kernel_"+kname):
1434 print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1436 self._copy_kernel_config(kname=kname)
1439 If we need to pass special options to the bootloader
1440 for this kernel put them into the environment
1442 if "boot/kernel/"+kname+"/kernelopts" in self.settings:
1443 myopts=self.settings["boot/kernel/"+kname+\
1446 if type(myopts) != types.StringType:
1447 myopts = string.join(myopts)
1448 self.env[kname+"_kernelopts"]=myopts
1451 self.env[kname+"_kernelopts"]=""
1453 if "boot/kernel/"+kname+"/extraversion" not in self.settings:
1454 self.settings["boot/kernel/"+kname+\
1457 self.env["clst_kextraversion"]=\
1458 self.settings["boot/kernel/"+kname+\
1461 self._copy_initramfs_overlay(kname=kname)
1463 """ Execute the script that builds the kernel """
1464 cmd("/bin/bash "+self.settings["controller_file"]+\
1466 "Runscript kernel build failed",env=self.env)
1468 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1469 if os.path.exists(self.settings["chroot_path"]+\
1470 "/tmp/initramfs_overlay/"):
1471 print "Cleaning up temporary overlay dir"
1472 cmd("rm -R "+self.settings["chroot_path"]+\
1473 "/tmp/initramfs_overlay/",env=self.env)
1475 touch(self.settings["autoresume_path"]+\
1476 "build_kernel_"+kname)
1479 Execute the script that cleans up the kernel build
1482 cmd("/bin/bash "+self.settings["controller_file"]+\
1484 "Runscript post-kmerge failed",env=self.env)
1486 def _copy_kernel_config(self, kname):
1487 if "boot/kernel/"+kname+"/config" in self.settings:
1488 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1490 raise CatalystError,\
1491 "Can't find kernel config: "+\
1492 self.settings["boot/kernel/"+kname+\
1496 cmd("cp "+self.settings["boot/kernel/"+kname+\
1498 self.settings["chroot_path"]+"/var/tmp/"+\
1500 "Couldn't copy kernel config: "+\
1501 self.settings["boot/kernel/"+kname+\
1502 "/config"],env=self.env)
1504 except CatalystError:
1507 def _copy_initramfs_overlay(self, kname):
1508 if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
1509 if os.path.exists(self.settings["boot/kernel/"+\
1510 kname+"/initramfs_overlay"]):
1511 print "Copying initramfs_overlay dir "+\
1512 self.settings["boot/kernel/"+kname+\
1513 "/initramfs_overlay"]
1516 self.settings["chroot_path"]+\
1517 "/tmp/initramfs_overlay/"+\
1518 self.settings["boot/kernel/"+kname+\
1519 "/initramfs_overlay"],env=self.env)
1521 cmd("cp -R "+self.settings["boot/kernel/"+\
1522 kname+"/initramfs_overlay"]+"/* "+\
1523 self.settings["chroot_path"]+\
1524 "/tmp/initramfs_overlay/"+\
1525 self.settings["boot/kernel/"+kname+\
1526 "/initramfs_overlay"],env=self.env)
1528 def bootloader(self):
1529 if "AUTORESUME" in self.settings \
1530 and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
1531 print "Resume point detected, skipping bootloader operation..."
1534 cmd("/bin/bash "+self.settings["controller_file"]+\
1535 " bootloader " + self.settings["target_path"],\
1536 "Bootloader script failed.",env=self.env)
1537 touch(self.settings["autoresume_path"]+"bootloader")
1538 except CatalystError:
1540 raise CatalystError,"Script aborting due to error."
1542 def livecd_update(self):
1543 if "AUTORESUME" in self.settings \
1544 and os.path.exists(self.settings["autoresume_path"]+\
1546 print "Resume point detected, skipping build_packages operation..."
1549 cmd("/bin/bash "+self.settings["controller_file"]+\
1550 " livecd-update","livecd-update failed.",env=self.env)
1551 touch(self.settings["autoresume_path"]+"livecd_update")
1553 except CatalystError:
1555 raise CatalystError,"build aborting due to livecd_update error."
1557 def clear_chroot(self):
1558 myemp=self.settings["chroot_path"]
1559 if os.path.isdir(myemp):
1560 print "Emptying directory",myemp
1562 stat the dir, delete the dir, recreate the dir and set
1563 the proper perms and ownership
1565 mystat=os.stat(myemp)
1566 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1567 """ There's no easy way to change flags recursively in python """
1568 if os.uname()[0] == "FreeBSD":
1569 os.system("chflags -R noschg "+myemp)
1570 shutil.rmtree(myemp)
1571 os.makedirs(myemp,0755)
1572 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1573 os.chmod(myemp,mystat[ST_MODE])
1575 def clear_packages(self):
1576 if "PKGCACHE" in self.settings:
1577 print "purging the pkgcache ..."
1579 myemp=self.settings["pkgcache_path"]
1580 if os.path.isdir(myemp):
1581 print "Emptying directory",myemp
1583 stat the dir, delete the dir, recreate the dir and set
1584 the proper perms and ownership
1586 mystat=os.stat(myemp)
1587 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1588 shutil.rmtree(myemp)
1589 os.makedirs(myemp,0755)
1590 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1591 os.chmod(myemp,mystat[ST_MODE])
1593 def clear_kerncache(self):
1594 if "KERNCACHE" in self.settings:
1595 print "purging the kerncache ..."
1597 myemp=self.settings["kerncache_path"]
1598 if os.path.isdir(myemp):
1599 print "Emptying directory",myemp
1601 stat the dir, delete the dir, recreate the dir and set
1602 the proper perms and ownership
1604 mystat=os.stat(myemp)
1605 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1606 shutil.rmtree(myemp)
1607 os.makedirs(myemp,0755)
1608 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1609 os.chmod(myemp,mystat[ST_MODE])
1611 def clear_autoresume(self):
1612 """ Clean resume points since they are no longer needed """
1613 if "AUTORESUME" in self.settings:
1614 print "Removing AutoResume Points: ..."
1615 myemp=self.settings["autoresume_path"]
1616 if os.path.isdir(myemp):
1617 if "AUTORESUME" in self.settings:
1618 print "Emptying directory",myemp
1620 stat the dir, delete the dir, recreate the dir and set
1621 the proper perms and ownership
1623 mystat=os.stat(myemp)
1624 if os.uname()[0] == "FreeBSD":
1625 cmd("chflags -R noschg "+myemp,\
1626 "Could not remove immutable flag for file "\
1628 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1629 shutil.rmtree(myemp)
1630 os.makedirs(myemp,0755)
1631 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1632 os.chmod(myemp,mystat[ST_MODE])
1634 def gen_contents_file(self,file):
1635 if os.path.exists(file+".CONTENTS"):
1636 os.remove(file+".CONTENTS")
1637 if "contents" in self.settings:
1638 if os.path.exists(file):
1639 myf=open(file+".CONTENTS","w")
1641 for i in self.settings["contents"].split():
1646 contents=generate_contents(file,contents_function=j,\
1647 verbose="VERBOSE" in self.settings)
1652 def gen_digest_file(self,file):
1653 if os.path.exists(file+".DIGESTS"):
1654 os.remove(file+".DIGESTS")
1655 if "digests" in self.settings:
1656 if os.path.exists(file):
1657 myf=open(file+".DIGESTS","w")
1659 for i in self.settings["digests"].split():
1663 for f in [file, file+'.CONTENTS']:
1664 if os.path.exists(f):
1666 for k in hash_map.keys():
1667 hash=generate_hash(f,hash_function=k,verbose=\
1668 "VERBOSE" in self.settings)
1672 hash=generate_hash(f,hash_function=j,verbose=\
1673 "VERBOSE" in self.settings)
1678 countdown(10,"Purging Caches ...")
1679 if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
1680 print "clearing autoresume ..."
1681 self.clear_autoresume()
1683 print "clearing chroot ..."
1686 if "PURGETMPONLY" not in self.settings:
1687 print "clearing package cache ..."
1688 self.clear_packages()
1690 print "clearing kerncache ..."
1691 self.clear_kerncache()
1693 # vim: ts=4 sw=4 sta et sts=4 ai