public inbox for gentoo-catalyst@lists.gentoo.org
 help / color / mirror / Atom feed
From: Brian Dolbec <dolsen@gentoo.org>
To: gentoo-catalyst@lists.gentoo.org
Cc: Brian Dolbec <dolsen@gentoo.org>
Subject: [gentoo-catalyst] [PATCH 3/4] rename the modules subpkg to targets, it better reflects what it contains
Date: Fri, 13 Dec 2013 19:20:10 -0800	[thread overview]
Message-ID: <1386991211-9296-4-git-send-email-dolsen@gentoo.org> (raw)
In-Reply-To: <1386991211-9296-1-git-send-email-dolsen@gentoo.org>

---
 catalyst/main.py                         |    6 +-
 catalyst/modules/__init__.py             |    1 -
 catalyst/modules/embedded_target.py      |   51 -
 catalyst/modules/generic_stage_target.py | 1691 ------------------------------
 catalyst/modules/generic_target.py       |   11 -
 catalyst/modules/grp_target.py           |  118 ---
 catalyst/modules/livecd_stage1_target.py |   75 --
 catalyst/modules/livecd_stage2_target.py |  146 ---
 catalyst/modules/netboot2_target.py      |  166 ---
 catalyst/modules/netboot_target.py       |  128 ---
 catalyst/modules/snapshot_target.py      |   91 --
 catalyst/modules/stage1_target.py        |   96 --
 catalyst/modules/stage2_target.py        |   62 --
 catalyst/modules/stage3_target.py        |   31 -
 catalyst/modules/stage4_target.py        |   43 -
 catalyst/modules/tinderbox_target.py     |   44 -
 catalyst/targets/__init__.py             |    1 +
 catalyst/targets/embedded_target.py      |   51 +
 catalyst/targets/generic_stage_target.py | 1691 ++++++++++++++++++++++++++++++
 catalyst/targets/generic_target.py       |   11 +
 catalyst/targets/grp_target.py           |  118 +++
 catalyst/targets/livecd_stage1_target.py |   75 ++
 catalyst/targets/livecd_stage2_target.py |  146 +++
 catalyst/targets/netboot2_target.py      |  166 +++
 catalyst/targets/netboot_target.py       |  128 +++
 catalyst/targets/snapshot_target.py      |   91 ++
 catalyst/targets/stage1_target.py        |   96 ++
 catalyst/targets/stage2_target.py        |   62 ++
 catalyst/targets/stage3_target.py        |   31 +
 catalyst/targets/stage4_target.py        |   43 +
 catalyst/targets/tinderbox_target.py     |   44 +
 31 files changed, 2757 insertions(+), 2757 deletions(-)
 delete mode 100644 catalyst/modules/__init__.py
 delete mode 100644 catalyst/modules/embedded_target.py
 delete mode 100644 catalyst/modules/generic_stage_target.py
 delete mode 100644 catalyst/modules/generic_target.py
 delete mode 100644 catalyst/modules/grp_target.py
 delete mode 100644 catalyst/modules/livecd_stage1_target.py
 delete mode 100644 catalyst/modules/livecd_stage2_target.py
 delete mode 100644 catalyst/modules/netboot2_target.py
 delete mode 100644 catalyst/modules/netboot_target.py
 delete mode 100644 catalyst/modules/snapshot_target.py
 delete mode 100644 catalyst/modules/stage1_target.py
 delete mode 100644 catalyst/modules/stage2_target.py
 delete mode 100644 catalyst/modules/stage3_target.py
 delete mode 100644 catalyst/modules/stage4_target.py
 delete mode 100644 catalyst/modules/tinderbox_target.py
 create mode 100644 catalyst/targets/__init__.py
 create mode 100644 catalyst/targets/embedded_target.py
 create mode 100644 catalyst/targets/generic_stage_target.py
 create mode 100644 catalyst/targets/generic_target.py
 create mode 100644 catalyst/targets/grp_target.py
 create mode 100644 catalyst/targets/livecd_stage1_target.py
 create mode 100644 catalyst/targets/livecd_stage2_target.py
 create mode 100644 catalyst/targets/netboot2_target.py
 create mode 100644 catalyst/targets/netboot_target.py
 create mode 100644 catalyst/targets/snapshot_target.py
 create mode 100644 catalyst/targets/stage1_target.py
 create mode 100644 catalyst/targets/stage2_target.py
 create mode 100644 catalyst/targets/stage3_target.py
 create mode 100644 catalyst/targets/stage4_target.py
 create mode 100644 catalyst/targets/tinderbox_target.py

diff --git a/catalyst/main.py b/catalyst/main.py
index 90ee722..28afc59 100644
--- a/catalyst/main.py
+++ b/catalyst/main.py
@@ -201,11 +201,11 @@ def import_modules():
 	targetmap={}
 
 	try:
-		module_dir = __selfpath__ + "/modules/"
+		module_dir = __selfpath__ + "/targets/"
 		for x in required_build_targets:
 			try:
 				fh=open(module_dir + x + ".py")
-				module=imp.load_module(x, fh,"modules/" + x + ".py",
+				module=imp.load_module(x, fh,"targets/" + x + ".py",
 					(".py", "r", imp.PY_SOURCE))
 				fh.close()
 
@@ -215,7 +215,7 @@ def import_modules():
 		for x in valid_build_targets:
 			try:
 				fh=open(module_dir + x + ".py")
-				module=imp.load_module(x, fh, "modules/" + x + ".py",
+				module=imp.load_module(x, fh, "targets/" + x + ".py",
 					(".py", "r", imp.PY_SOURCE))
 				module.register(targetmap)
 				fh.close()
diff --git a/catalyst/modules/__init__.py b/catalyst/modules/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/catalyst/modules/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/catalyst/modules/embedded_target.py b/catalyst/modules/embedded_target.py
deleted file mode 100644
index 7cee7a6..0000000
--- a/catalyst/modules/embedded_target.py
+++ /dev/null
@@ -1,51 +0,0 @@
-"""
-Enbedded target, similar to the stage2 target, builds upon a stage2 tarball.
-
-A stage2 tarball is unpacked, but instead
-of building a stage3, it emerges @system into another directory
-inside the stage2 system.  This way, we do not have to emerge GCC/portage
-into the staged system.
-It may sound complicated but basically it runs
-ROOT=/tmp/submerge emerge --something foo bar .
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-import os,string,imp,types,shutil
-from catalyst.support import *
-from generic_stage_target import *
-from stat import *
-
-class embedded_target(generic_stage_target):
-	"""
-	Builder class for embedded target
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=[]
-		self.valid_values=[]
-		self.valid_values.extend(["embedded/empty","embedded/rm","embedded/unmerge","embedded/fs-prepare","embedded/fs-finish","embedded/mergeroot","embedded/packages","embedded/fs-type","embedded/runscript","boot/kernel","embedded/linuxrc"])
-		self.valid_values.extend(["embedded/use"])
-		if "embedded/fs-type" in addlargs:
-			self.valid_values.append("embedded/fs-ops")
-
-		generic_stage_target.__init__(self,spec,addlargs)
-		self.set_build_kernel_vars(addlargs)
-
-	def set_action_sequence(self):
-		self.settings["action_sequence"]=["dir_setup","unpack","unpack_snapshot",\
-					"config_profile_link","setup_confdir",\
-					"portage_overlay","bind","chroot_setup",\
-					"setup_environment","build_kernel","build_packages",\
-					"bootloader","root_overlay","fsscript","unmerge",\
-					"unbind","remove","empty","clean","capture","clear_autoresume"]
-
-	def set_stage_path(self):
-		self.settings["stage_path"]=normpath(self.settings["chroot_path"]+"/tmp/mergeroot")
-		print "embedded stage path is "+self.settings["stage_path"]
-
-	def set_root_path(self):
-		self.settings["root_path"]=normpath("/tmp/mergeroot")
-		print "embedded root path is "+self.settings["root_path"]
-
-def register(foo):
-	foo.update({"embedded":embedded_target})
-	return foo
diff --git a/catalyst/modules/generic_stage_target.py b/catalyst/modules/generic_stage_target.py
deleted file mode 100644
index 5200d8a..0000000
--- a/catalyst/modules/generic_stage_target.py
+++ /dev/null
@@ -1,1691 +0,0 @@
-import os,string,imp,types,shutil
-from catalyst.support import *
-from generic_target import *
-from stat import *
-from catalyst.lock import LockDir
-
-class generic_stage_target(generic_target):
-	"""
-	This class does all of the chroot setup, copying of files, etc. It is
-	the driver class for pretty much everything that Catalyst does.
-	"""
-	def __init__(self,myspec,addlargs):
-		self.required_values.extend(["version_stamp","target","subarch",\
-			"rel_type","profile","snapshot","source_subpath"])
-
-		self.valid_values.extend(["version_stamp","target","subarch",\
-			"rel_type","profile","snapshot","source_subpath","portage_confdir",\
-			"cflags","cxxflags","ldflags","cbuild","hostuse","portage_overlay",\
-			"distcc_hosts","makeopts","pkgcache_path","kerncache_path"])
-
-		self.set_valid_build_kernel_vars(addlargs)
-		generic_target.__init__(self,myspec,addlargs)
-
-		"""
-		The semantics of subarchmap and machinemap changed a bit in 2.0.3 to
-		work better with vapier's CBUILD stuff. I've removed the "monolithic"
-		machinemap from this file and split up its contents amongst the
-		various arch/foo.py files.
-
-		When register() is called on each module in the arch/ dir, it now
-		returns a tuple instead of acting on the subarchmap dict that is
-		passed to it. The tuple contains the values that were previously
-		added to subarchmap as well as a new list of CHOSTs that go along
-		with that arch. This allows us to build machinemap on the fly based
-		on the keys in subarchmap and the values of the 2nd list returned
-		(tmpmachinemap).
-
-		Also, after talking with vapier. I have a slightly better idea of what
-		certain variables are used for and what they should be set to. Neither
-		'buildarch' or 'hostarch' are used directly, so their value doesn't
-		really matter. They are just compared to determine if we are
-		cross-compiling. Because of this, they are just set to the name of the
-		module in arch/ that the subarch is part of to make things simpler.
-		The entire build process is still based off of 'subarch' like it was
-		previously. -agaffney
-		"""
-
-		self.archmap = {}
-		self.subarchmap = {}
-		machinemap = {}
-		arch_dir = self.settings["PythonDir"] + "/arch/"
-		for x in [x[:-3] for x in os.listdir(arch_dir) if x.endswith(".py")]:
-			try:
-				fh=open(arch_dir + x + ".py")
-				"""
-				This next line loads the plugin as a module and assigns it to
-				archmap[x]
-				"""
-				self.archmap[x]=imp.load_module(x,fh,"../arch/" + x + ".py",
-					(".py", "r", imp.PY_SOURCE))
-				"""
-				This next line registers all the subarches supported in the
-				plugin
-				"""
-				tmpsubarchmap, tmpmachinemap = self.archmap[x].register()
-				self.subarchmap.update(tmpsubarchmap)
-				for machine in tmpmachinemap:
-					machinemap[machine] = x
-				for subarch in tmpsubarchmap:
-					machinemap[subarch] = x
-				fh.close()
-			except IOError:
-				"""
-				This message should probably change a bit, since everything in
-				the dir should load just fine. If it doesn't, it's probably a
-				syntax error in the module
-				"""
-				msg("Can't find/load " + x + ".py plugin in " + arch_dir)
-
-		if "chost" in self.settings:
-			hostmachine = self.settings["chost"].split("-")[0]
-			if hostmachine not in machinemap:
-				raise CatalystError, "Unknown host machine type "+hostmachine
-			self.settings["hostarch"]=machinemap[hostmachine]
-		else:
-			hostmachine = self.settings["subarch"]
-			if hostmachine in machinemap:
-				hostmachine = machinemap[hostmachine]
-			self.settings["hostarch"]=hostmachine
-		if "cbuild" in self.settings:
-			buildmachine = self.settings["cbuild"].split("-")[0]
-		else:
-			buildmachine = os.uname()[4]
-		if buildmachine not in machinemap:
-			raise CatalystError, "Unknown build machine type "+buildmachine
-		self.settings["buildarch"]=machinemap[buildmachine]
-		self.settings["crosscompile"]=(self.settings["hostarch"]!=\
-			self.settings["buildarch"])
-
-		""" Call arch constructor, pass our settings """
-		try:
-			self.arch=self.subarchmap[self.settings["subarch"]](self.settings)
-		except KeyError:
-			print "Invalid subarch: "+self.settings["subarch"]
-			print "Choose one of the following:",
-			for x in self.subarchmap:
-				print x,
-			print
-			sys.exit(2)
-
-		print "Using target:",self.settings["target"]
-		""" Print a nice informational message """
-		if self.settings["buildarch"]==self.settings["hostarch"]:
-			print "Building natively for",self.settings["hostarch"]
-		elif self.settings["crosscompile"]:
-			print "Cross-compiling on",self.settings["buildarch"],\
-				"for different machine type",self.settings["hostarch"]
-		else:
-			print "Building on",self.settings["buildarch"],\
-				"for alternate personality type",self.settings["hostarch"]
-
-		""" This must be set first as other set_ options depend on this """
-		self.set_spec_prefix()
-
-		""" Define all of our core variables """
-		self.set_target_profile()
-		self.set_target_subpath()
-		self.set_source_subpath()
-
-		""" Set paths """
-		self.set_snapshot_path()
-		self.set_root_path()
-		self.set_source_path()
-		self.set_snapcache_path()
-		self.set_chroot_path()
-		self.set_autoresume_path()
-		self.set_dest_path()
-		self.set_stage_path()
-		self.set_target_path()
-
-		self.set_controller_file()
-		self.set_action_sequence()
-		self.set_use()
-		self.set_cleanables()
-		self.set_iso_volume_id()
-		self.set_build_kernel_vars()
-		self.set_fsscript()
-		self.set_install_mask()
-		self.set_rcadd()
-		self.set_rcdel()
-		self.set_cdtar()
-		self.set_fstype()
-		self.set_fsops()
-		self.set_iso()
-		self.set_packages()
-		self.set_rm()
-		self.set_linuxrc()
-		self.set_busybox_config()
-		self.set_overlay()
-		self.set_portage_overlay()
-		self.set_root_overlay()
-
-		"""
-		This next line checks to make sure that the specified variables exist
-		on disk.
-		"""
-		#pdb.set_trace()
-		file_locate(self.settings,["source_path","snapshot_path","distdir"],\
-			expand=0)
-		""" If we are using portage_confdir, check that as well. """
-		if "portage_confdir" in self.settings:
-			file_locate(self.settings,["portage_confdir"],expand=0)
-
-		""" Setup our mount points """
-		if "SNAPCACHE" in self.settings:
-			self.mounts=["/proc","/dev","/usr/portage","/usr/portage/distfiles","/var/tmp/portage"]
-			self.mountmap={"/proc":"/proc","/dev":"/dev","/dev/pts":"/dev/pts",\
-				"/usr/portage":self.settings["snapshot_cache_path"]+"/portage",\
-				"/usr/portage/distfiles":self.settings["distdir"],"/var/tmp/portage":"tmpfs"}
-		else:
-			self.mounts=["proc","dev", "distdir", "port_tmpdir"]
-			self.mountmap={"proc":"/proc", "dev":"/dev", "pts":"/dev/pts",
-				"distdir":self.settings["distdir"], "port_tmpdir":"tmpfs"}
-		if os.uname()[0] == "Linux":
-			self.mounts.append("pts")
-
-		self.set_mounts()
-
-		"""
-		Configure any user specified options (either in catalyst.conf or on
-		the command line).
-		"""
-		if "PKGCACHE" in self.settings:
-			self.set_pkgcache_path()
-			print "Location of the package cache is "+\
-				self.settings["pkgcache_path"]
-			self.mounts.append("packagedir")
-			self.mountmap["packagedir"] = self.settings["pkgcache_path"]
-
-		if "KERNCACHE" in self.settings:
-			self.set_kerncache_path()
-			print "Location of the kerncache is "+\
-				self.settings["kerncache_path"]
-			self.mounts.append("kerncache")
-			self.mountmap["kerncache"]=self.settings["kerncache_path"]
-
-		if "CCACHE" in self.settings:
-			if "CCACHE_DIR" in os.environ:
-				ccdir=os.environ["CCACHE_DIR"]
-				del os.environ["CCACHE_DIR"]
-			else:
-				ccdir="/root/.ccache"
-			if not os.path.isdir(ccdir):
-				raise CatalystError,\
-					"Compiler cache support can't be enabled (can't find "+\
-					ccdir+")"
-			self.mounts.append("ccache")
-			self.mountmap["ccache"]=ccdir
-			""" for the chroot: """
-			self.env["CCACHE_DIR"]="/var/tmp/ccache"
-
-		if "ICECREAM" in self.settings:
-			self.mounts.append("/var/cache/icecream")
-			self.mountmap["/var/cache/icecream"]="/var/cache/icecream"
-			self.env["PATH"]="/usr/lib/icecc/bin:"+self.env["PATH"]
-
-		if "port_logdir" in self.settings:
-			self.mounts.append("/var/log/portage")
-			self.mountmap["/var/log/portage"]=self.settings["port_logdir"]
-			self.env["PORT_LOGDIR"]="/var/log/portage"
-			self.env["PORT_LOGDIR_CLEAN"]='find "${PORT_LOGDIR}" -type f ! -name "summary.log*" -mtime +30 -delete'
-
-	def override_cbuild(self):
-		if "CBUILD" in self.makeconf:
-			self.settings["CBUILD"]=self.makeconf["CBUILD"]
-
-	def override_chost(self):
-		if "CHOST" in self.makeconf:
-			self.settings["CHOST"]=self.makeconf["CHOST"]
-
-	def override_cflags(self):
-		if "CFLAGS" in self.makeconf:
-			self.settings["CFLAGS"]=self.makeconf["CFLAGS"]
-
-	def override_cxxflags(self):
-		if "CXXFLAGS" in self.makeconf:
-			self.settings["CXXFLAGS"]=self.makeconf["CXXFLAGS"]
-
-	def override_ldflags(self):
-		if "LDFLAGS" in self.makeconf:
-			self.settings["LDFLAGS"]=self.makeconf["LDFLAGS"]
-
-	def set_install_mask(self):
-		if "install_mask" in self.settings:
-			if type(self.settings["install_mask"])!=types.StringType:
-				self.settings["install_mask"]=\
-					string.join(self.settings["install_mask"])
-
-	def set_spec_prefix(self):
-		self.settings["spec_prefix"]=self.settings["target"]
-
-	def set_target_profile(self):
-		self.settings["target_profile"]=self.settings["profile"]
-
-	def set_target_subpath(self):
-		self.settings["target_subpath"]=self.settings["rel_type"]+"/"+\
-				self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
-				self.settings["version_stamp"]
-
-	def set_source_subpath(self):
-		if type(self.settings["source_subpath"])!=types.StringType:
-			raise CatalystError,\
-				"source_subpath should have been a string. Perhaps you have something wrong in your spec file?"
-
-	def set_pkgcache_path(self):
-		if "pkgcache_path" in self.settings:
-			if type(self.settings["pkgcache_path"])!=types.StringType:
-				self.settings["pkgcache_path"]=\
-					normpath(string.join(self.settings["pkgcache_path"]))
-		else:
-			self.settings["pkgcache_path"]=\
-				normpath(self.settings["storedir"]+"/packages/"+\
-				self.settings["target_subpath"]+"/")
-
-	def set_kerncache_path(self):
-		if "kerncache_path" in self.settings:
-			if type(self.settings["kerncache_path"])!=types.StringType:
-				self.settings["kerncache_path"]=\
-					normpath(string.join(self.settings["kerncache_path"]))
-		else:
-			self.settings["kerncache_path"]=normpath(self.settings["storedir"]+\
-				"/kerncache/"+self.settings["target_subpath"]+"/")
-
-	def set_target_path(self):
-		self.settings["target_path"]=normpath(self.settings["storedir"]+\
-			"/builds/"+self.settings["target_subpath"]+".tar.bz2")
-		if "AUTORESUME" in self.settings\
-			and os.path.exists(self.settings["autoresume_path"]+\
-				"setup_target_path"):
-			print \
-				"Resume point detected, skipping target path setup operation..."
-		else:
-			""" First clean up any existing target stuff """
-			# XXX WTF are we removing the old tarball before we start building the
-			# XXX new one? If the build fails, you don't want to be left with
-			# XXX nothing at all
-#			if os.path.isfile(self.settings["target_path"]):
-#				cmd("rm -f "+self.settings["target_path"],\
-#					"Could not remove existing file: "\
-#					+self.settings["target_path"],env=self.env)
-			touch(self.settings["autoresume_path"]+"setup_target_path")
-
-			if not os.path.exists(self.settings["storedir"]+"/builds/"):
-				os.makedirs(self.settings["storedir"]+"/builds/")
-
-	def set_fsscript(self):
-		if self.settings["spec_prefix"]+"/fsscript" in self.settings:
-			self.settings["fsscript"]=\
-				self.settings[self.settings["spec_prefix"]+"/fsscript"]
-			del self.settings[self.settings["spec_prefix"]+"/fsscript"]
-
-	def set_rcadd(self):
-		if self.settings["spec_prefix"]+"/rcadd" in self.settings:
-			self.settings["rcadd"]=\
-				self.settings[self.settings["spec_prefix"]+"/rcadd"]
-			del self.settings[self.settings["spec_prefix"]+"/rcadd"]
-
-	def set_rcdel(self):
-		if self.settings["spec_prefix"]+"/rcdel" in self.settings:
-			self.settings["rcdel"]=\
-				self.settings[self.settings["spec_prefix"]+"/rcdel"]
-			del self.settings[self.settings["spec_prefix"]+"/rcdel"]
-
-	def set_cdtar(self):
-		if self.settings["spec_prefix"]+"/cdtar" in self.settings:
-			self.settings["cdtar"]=\
-				normpath(self.settings[self.settings["spec_prefix"]+"/cdtar"])
-			del self.settings[self.settings["spec_prefix"]+"/cdtar"]
-
-	def set_iso(self):
-		if self.settings["spec_prefix"]+"/iso" in self.settings:
-			if self.settings[self.settings["spec_prefix"]+"/iso"].startswith('/'):
-				self.settings["iso"]=\
-					normpath(self.settings[self.settings["spec_prefix"]+"/iso"])
-			else:
-				# This automatically prepends the build dir to the ISO output path
-				# if it doesn't start with a /
-				self.settings["iso"] = normpath(self.settings["storedir"] + \
-					"/builds/" + self.settings["rel_type"] + "/" + \
-					self.settings[self.settings["spec_prefix"]+"/iso"])
-			del self.settings[self.settings["spec_prefix"]+"/iso"]
-
-	def set_fstype(self):
-		if self.settings["spec_prefix"]+"/fstype" in self.settings:
-			self.settings["fstype"]=\
-				self.settings[self.settings["spec_prefix"]+"/fstype"]
-			del self.settings[self.settings["spec_prefix"]+"/fstype"]
-
-		if "fstype" not in self.settings:
-			self.settings["fstype"]="normal"
-			for x in self.valid_values:
-				if x ==  self.settings["spec_prefix"]+"/fstype":
-					print "\n"+self.settings["spec_prefix"]+\
-						"/fstype is being set to the default of \"normal\"\n"
-
-	def set_fsops(self):
-		if "fstype" in self.settings:
-			self.valid_values.append("fsops")
-			if self.settings["spec_prefix"]+"/fsops" in self.settings:
-				self.settings["fsops"]=\
-					self.settings[self.settings["spec_prefix"]+"/fsops"]
-				del self.settings[self.settings["spec_prefix"]+"/fsops"]
-
-	def set_source_path(self):
-		if "SEEDCACHE" in self.settings\
-			and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+\
-				self.settings["source_subpath"]+"/")):
-			self.settings["source_path"]=normpath(self.settings["storedir"]+\
-				"/tmp/"+self.settings["source_subpath"]+"/")
-		else:
-			self.settings["source_path"]=normpath(self.settings["storedir"]+\
-				"/builds/"+self.settings["source_subpath"]+".tar.bz2")
-			if os.path.isfile(self.settings["source_path"]):
-				# XXX: Is this even necessary if the previous check passes?
-				if os.path.exists(self.settings["source_path"]):
-					self.settings["source_path_hash"]=\
-						generate_hash(self.settings["source_path"],\
-						hash_function=self.settings["hash_function"],\
-						verbose=False)
-		print "Source path set to "+self.settings["source_path"]
-		if os.path.isdir(self.settings["source_path"]):
-			print "\tIf this is not desired, remove this directory or turn off"
-			print "\tseedcache in the options of catalyst.conf the source path"
-			print "\twill then be "+\
-				normpath(self.settings["storedir"]+"/builds/"+\
-				self.settings["source_subpath"]+".tar.bz2\n")
-
-	def set_dest_path(self):
-		if "root_path" in self.settings:
-			self.settings["destpath"]=normpath(self.settings["chroot_path"]+\
-				self.settings["root_path"])
-		else:
-			self.settings["destpath"]=normpath(self.settings["chroot_path"])
-
-	def set_cleanables(self):
-		self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/tmp/*",\
-			"/root/*", self.settings["portdir"]]
-
-	def set_snapshot_path(self):
-		self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
-			"/snapshots/" + self.settings["snapshot_name"] +
-			self.settings["snapshot"]+".tar.xz")
-
-		if os.path.exists(self.settings["snapshot_path"]):
-			self.settings["snapshot_path_hash"]=\
-				generate_hash(self.settings["snapshot_path"],\
-				hash_function=self.settings["hash_function"],verbose=False)
-		else:
-			self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
-				"/snapshots/" + self.settings["snapshot_name"] +
-				self.settings["snapshot"]+".tar.bz2")
-
-			if os.path.exists(self.settings["snapshot_path"]):
-				self.settings["snapshot_path_hash"]=\
-					generate_hash(self.settings["snapshot_path"],\
-					hash_function=self.settings["hash_function"],verbose=False)
-
-	def set_snapcache_path(self):
-		if "SNAPCACHE" in self.settings:
-			self.settings["snapshot_cache_path"]=\
-				normpath(self.settings["snapshot_cache"]+"/"+\
-				self.settings["snapshot"]+"/")
-			self.snapcache_lock=\
-				LockDir(self.settings["snapshot_cache_path"])
-			print "Caching snapshot to "+self.settings["snapshot_cache_path"]
-
-	def set_chroot_path(self):
-		"""
-		NOTE: the trailing slash is very important!
-		Things *will* break without it!
-		"""
-		self.settings["chroot_path"]=normpath(self.settings["storedir"]+\
-			"/tmp/"+self.settings["target_subpath"]+"/")
-		self.chroot_lock=LockDir(self.settings["chroot_path"])
-
-	def set_autoresume_path(self):
-		self.settings["autoresume_path"]=normpath(self.settings["storedir"]+\
-			"/tmp/"+self.settings["rel_type"]+"/"+".autoresume-"+\
-			self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
-			self.settings["version_stamp"]+"/")
-		if "AUTORESUME" in self.settings:
-			print "The autoresume path is " + self.settings["autoresume_path"]
-		if not os.path.exists(self.settings["autoresume_path"]):
-			os.makedirs(self.settings["autoresume_path"],0755)
-
-	def set_controller_file(self):
-		self.settings["controller_file"]=normpath(self.settings["sharedir"]+\
-			"/targets/"+self.settings["target"]+"/"+self.settings["target"]+\
-			"-controller.sh")
-
-	def set_iso_volume_id(self):
-		if self.settings["spec_prefix"]+"/volid" in self.settings:
-			self.settings["iso_volume_id"]=\
-				self.settings[self.settings["spec_prefix"]+"/volid"]
-			if len(self.settings["iso_volume_id"])>32:
-				raise CatalystError,\
-					"ISO volume ID must not exceed 32 characters."
-		else:
-			self.settings["iso_volume_id"]="catalyst "+self.settings["snapshot"]
-
-	def set_action_sequence(self):
-		""" Default action sequence for run method """
-		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
-				"setup_confdir","portage_overlay",\
-				"base_dirs","bind","chroot_setup","setup_environment",\
-				"run_local","preclean","unbind","clean"]
-#		if "TARBALL" in self.settings or \
-#			"FETCH" not in self.settings:
-		if "FETCH" not in self.settings:
-			self.settings["action_sequence"].append("capture")
-		self.settings["action_sequence"].append("clear_autoresume")
-
-	def set_use(self):
-		if self.settings["spec_prefix"]+"/use" in self.settings:
-			self.settings["use"]=\
-				self.settings[self.settings["spec_prefix"]+"/use"]
-			del self.settings[self.settings["spec_prefix"]+"/use"]
-		if "use" not in self.settings:
-			self.settings["use"]=""
-		if type(self.settings["use"])==types.StringType:
-			self.settings["use"]=self.settings["use"].split()
-
-		# Force bindist when options ask for it
-		if "BINDIST" in self.settings:
-			self.settings["use"].append("bindist")
-
-	def set_stage_path(self):
-		self.settings["stage_path"]=normpath(self.settings["chroot_path"])
-
-	def set_mounts(self):
-		pass
-
-	def set_packages(self):
-		pass
-
-	def set_rm(self):
-		if self.settings["spec_prefix"]+"/rm" in self.settings:
-			if type(self.settings[self.settings["spec_prefix"]+\
-				"/rm"])==types.StringType:
-				self.settings[self.settings["spec_prefix"]+"/rm"]=\
-					self.settings[self.settings["spec_prefix"]+"/rm"].split()
-
-	def set_linuxrc(self):
-		if self.settings["spec_prefix"]+"/linuxrc" in self.settings:
-			if type(self.settings[self.settings["spec_prefix"]+\
-				"/linuxrc"])==types.StringType:
-				self.settings["linuxrc"]=\
-					self.settings[self.settings["spec_prefix"]+"/linuxrc"]
-				del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
-
-	def set_busybox_config(self):
-		if self.settings["spec_prefix"]+"/busybox_config" in self.settings:
-			if type(self.settings[self.settings["spec_prefix"]+\
-				"/busybox_config"])==types.StringType:
-				self.settings["busybox_config"]=\
-					self.settings[self.settings["spec_prefix"]+"/busybox_config"]
-				del self.settings[self.settings["spec_prefix"]+"/busybox_config"]
-
-	def set_portage_overlay(self):
-		if "portage_overlay" in self.settings:
-			if type(self.settings["portage_overlay"])==types.StringType:
-				self.settings["portage_overlay"]=\
-					self.settings["portage_overlay"].split()
-			print "portage_overlay directories are set to: \""+\
-				string.join(self.settings["portage_overlay"])+"\""
-
-	def set_overlay(self):
-		if self.settings["spec_prefix"]+"/overlay" in self.settings:
-			if type(self.settings[self.settings["spec_prefix"]+\
-				"/overlay"])==types.StringType:
-				self.settings[self.settings["spec_prefix"]+"/overlay"]=\
-					self.settings[self.settings["spec_prefix"]+\
-					"/overlay"].split()
-
-	def set_root_overlay(self):
-		if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
-			if type(self.settings[self.settings["spec_prefix"]+\
-				"/root_overlay"])==types.StringType:
-				self.settings[self.settings["spec_prefix"]+"/root_overlay"]=\
-					self.settings[self.settings["spec_prefix"]+\
-					"/root_overlay"].split()
-
-	def set_root_path(self):
-		""" ROOT= variable for emerges """
-		self.settings["root_path"]="/"
-
-	def set_valid_build_kernel_vars(self,addlargs):
-		if "boot/kernel" in addlargs:
-			if type(addlargs["boot/kernel"])==types.StringType:
-				loopy=[addlargs["boot/kernel"]]
-			else:
-				loopy=addlargs["boot/kernel"]
-
-			for x in loopy:
-				self.valid_values.append("boot/kernel/"+x+"/aliases")
-				self.valid_values.append("boot/kernel/"+x+"/config")
-				self.valid_values.append("boot/kernel/"+x+"/console")
-				self.valid_values.append("boot/kernel/"+x+"/extraversion")
-				self.valid_values.append("boot/kernel/"+x+"/gk_action")
-				self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
-				self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
-				self.valid_values.append("boot/kernel/"+x+"/machine_type")
-				self.valid_values.append("boot/kernel/"+x+"/sources")
-				self.valid_values.append("boot/kernel/"+x+"/softlevel")
-				self.valid_values.append("boot/kernel/"+x+"/use")
-				self.valid_values.append("boot/kernel/"+x+"/packages")
-				if "boot/kernel/"+x+"/packages" in addlargs:
-					if type(addlargs["boot/kernel/"+x+\
-						"/packages"])==types.StringType:
-						addlargs["boot/kernel/"+x+"/packages"]=\
-							[addlargs["boot/kernel/"+x+"/packages"]]
-
-	def set_build_kernel_vars(self):
-		if self.settings["spec_prefix"]+"/gk_mainargs" in self.settings:
-			self.settings["gk_mainargs"]=\
-				self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
-			del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
-
-	def kill_chroot_pids(self):
-		print "Checking for processes running in chroot and killing them."
-
-		"""
-		Force environment variables to be exported so script can see them
-		"""
-		self.setup_environment()
-
-		if os.path.exists(self.settings["sharedir"]+\
-			"/targets/support/kill-chroot-pids.sh"):
-			cmd("/bin/bash "+self.settings["sharedir"]+\
-				"/targets/support/kill-chroot-pids.sh",\
-				"kill-chroot-pids script failed.",env=self.env)
-
-	def mount_safety_check(self):
-		mypath=self.settings["chroot_path"]
-
-		"""
-		Check and verify that none of our paths in mypath are mounted. We don't
-		want to clean up with things still mounted, and this allows us to check.
-		Returns 1 on ok, 0 on "something is still mounted" case.
-		"""
-
-		if not os.path.exists(mypath):
-			return
-
-		for x in self.mounts:
-			if not os.path.exists(mypath + self.mountmap[x]):
-				continue
-
-			if ismount(mypath +self.mountmap[x]):
-				""" Something is still mounted "" """
-				try:
-					print self.mountmap[x] + " is still mounted; performing auto-bind-umount...",
-					""" Try to umount stuff ourselves """
-					self.unbind()
-					if ismount(mypath + self.mountmap[x]):
-						raise CatalystError, "Auto-unbind failed for " + self.mountmap[x]
-					else:
-						print "Auto-unbind successful..."
-				except CatalystError:
-					raise CatalystError, "Unable to auto-unbind " + self.mountmap[x]
-
-	def unpack(self):
-		unpack=True
-
-		clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+\
-			"unpack")
-
-		if "SEEDCACHE" in self.settings:
-			if os.path.isdir(self.settings["source_path"]):
-				""" SEEDCACHE Is a directory, use rsync """
-				unpack_cmd="rsync -a --delete "+self.settings["source_path"]+\
-					" "+self.settings["chroot_path"]
-				display_msg="\nStarting rsync from "+\
-					self.settings["source_path"]+"\nto "+\
-					self.settings["chroot_path"]+\
-					" (This may take some time) ...\n"
-				error_msg="Rsync of "+self.settings["source_path"]+" to "+\
-					self.settings["chroot_path"]+" failed."
-			else:
-				""" SEEDCACHE is a not a directory, try untar'ing """
-				print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
-				display_msg="\nStarting tar extract from "+\
-					self.settings["source_path"]+"\nto "+\
-					self.settings["chroot_path"]+\
-						" (This may take some time) ...\n"
-				if "bz2" == self.settings["chroot_path"][-3:]:
-					unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
-						self.settings["chroot_path"]
-				else:
-					unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
-						self.settings["chroot_path"]
-				error_msg="Tarball extraction of "+\
-					self.settings["source_path"]+" to "+\
-					self.settings["chroot_path"]+" failed."
-		else:
-			""" No SEEDCACHE, use tar """
-			display_msg="\nStarting tar extract from "+\
-				self.settings["source_path"]+"\nto "+\
-				self.settings["chroot_path"]+\
-				" (This may take some time) ...\n"
-			if "bz2" == self.settings["chroot_path"][-3:]:
-				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
-					self.settings["chroot_path"]
-			else:
-				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
-					self.settings["chroot_path"]
-			error_msg="Tarball extraction of "+self.settings["source_path"]+\
-				" to "+self.settings["chroot_path"]+" failed."
-
-		if "AUTORESUME" in self.settings:
-			if os.path.isdir(self.settings["source_path"]) \
-				and os.path.exists(self.settings["autoresume_path"]+"unpack"):
-				""" Autoresume is valid, SEEDCACHE is valid """
-				unpack=False
-				invalid_snapshot=False
-
-			elif os.path.isfile(self.settings["source_path"]) \
-				and self.settings["source_path_hash"]==clst_unpack_hash:
-				""" Autoresume is valid, tarball is valid """
-				unpack=False
-				invalid_snapshot=True
-
-			elif os.path.isdir(self.settings["source_path"]) \
-				and not os.path.exists(self.settings["autoresume_path"]+\
-				"unpack"):
-				""" Autoresume is invalid, SEEDCACHE """
-				unpack=True
-				invalid_snapshot=False
-
-			elif os.path.isfile(self.settings["source_path"]) \
-				and self.settings["source_path_hash"]!=clst_unpack_hash:
-				""" Autoresume is invalid, tarball """
-				unpack=True
-				invalid_snapshot=True
-		else:
-			""" No autoresume, SEEDCACHE """
-			if "SEEDCACHE" in self.settings:
-				""" SEEDCACHE so let's run rsync and let it clean up """
-				if os.path.isdir(self.settings["source_path"]):
-					unpack=True
-					invalid_snapshot=False
-				elif os.path.isfile(self.settings["source_path"]):
-					""" Tarball so unpack and remove anything already there """
-					unpack=True
-					invalid_snapshot=True
-				""" No autoresume, no SEEDCACHE """
-			else:
-				""" Tarball so unpack and remove anything already there """
-				if os.path.isfile(self.settings["source_path"]):
-					unpack=True
-					invalid_snapshot=True
-				elif os.path.isdir(self.settings["source_path"]):
-					""" We should never reach this, so something is very wrong """
-					raise CatalystError,\
-						"source path is a dir but seedcache is not enabled"
-
-		if unpack:
-			self.mount_safety_check()
-
-			if invalid_snapshot:
-				if "AUTORESUME" in self.settings:
-					print "No Valid Resume point detected, cleaning up..."
-
-				self.clear_autoresume()
-				self.clear_chroot()
-
-			if not os.path.exists(self.settings["chroot_path"]):
-				os.makedirs(self.settings["chroot_path"])
-
-			if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
-				os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
-
-			if "PKGCACHE" in self.settings:
-				if not os.path.exists(self.settings["pkgcache_path"]):
-					os.makedirs(self.settings["pkgcache_path"],0755)
-
-			if "KERNCACHE" in self.settings:
-				if not os.path.exists(self.settings["kerncache_path"]):
-					os.makedirs(self.settings["kerncache_path"],0755)
-
-			print display_msg
-			cmd(unpack_cmd,error_msg,env=self.env)
-
-			if "source_path_hash" in self.settings:
-				myf=open(self.settings["autoresume_path"]+"unpack","w")
-				myf.write(self.settings["source_path_hash"])
-				myf.close()
-			else:
-				touch(self.settings["autoresume_path"]+"unpack")
-		else:
-			print "Resume point detected, skipping unpack operation..."
-
-	def unpack_snapshot(self):
-		unpack=True
-		snapshot_hash=read_from_clst(self.settings["autoresume_path"]+\
-			"unpack_portage")
-
-		if "SNAPCACHE" in self.settings:
-			snapshot_cache_hash=\
-				read_from_clst(self.settings["snapshot_cache_path"]+\
-				"catalyst-hash")
-			destdir=self.settings["snapshot_cache_path"]
-			if "bz2" == self.settings["chroot_path"][-3:]:
-				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+destdir
-			else:
-				unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+destdir
-			unpack_errmsg="Error unpacking snapshot"
-			cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+\
-				self.settings["snapshot_cache_path"]+\
-				" (This can take a long time)..."
-			cleanup_errmsg="Error removing existing snapshot cache directory."
-			self.snapshot_lock_object=self.snapcache_lock
-
-			if self.settings["snapshot_path_hash"]==snapshot_cache_hash:
-				print "Valid snapshot cache, skipping unpack of portage tree..."
-				unpack=False
-		else:
-			destdir=normpath(self.settings["chroot_path"] + self.settings["portdir"])
-			cleanup_errmsg="Error removing existing snapshot directory."
-			cleanup_msg=\
-				"Cleaning up existing portage tree (This can take a long time)..."
-			if "bz2" == self.settings["chroot_path"][-3:]:
-				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+\
-					self.settings["chroot_path"]+"/usr"
-			else:
-				unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+\
-					self.settings["chroot_path"]+"/usr"
-			unpack_errmsg="Error unpacking snapshot"
-
-			if "AUTORESUME" in self.settings \
-				and os.path.exists(self.settings["chroot_path"]+\
-					self.settings["portdir"]) \
-				and os.path.exists(self.settings["autoresume_path"]\
-					+"unpack_portage") \
-				and self.settings["snapshot_path_hash"] == snapshot_hash:
-					print \
-						"Valid Resume point detected, skipping unpack of portage tree..."
-					unpack=False
-
-		if unpack:
-			if "SNAPCACHE" in self.settings:
-				self.snapshot_lock_object.write_lock()
-			if os.path.exists(destdir):
-				print cleanup_msg
-				cleanup_cmd="rm -rf "+destdir
-				cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
-			if not os.path.exists(destdir):
-				os.makedirs(destdir,0755)
-
-			print "Unpacking portage tree (This can take a long time) ..."
-			cmd(unpack_cmd,unpack_errmsg,env=self.env)
-
-			if "SNAPCACHE" in self.settings:
-				myf=open(self.settings["snapshot_cache_path"]+"catalyst-hash","w")
-				myf.write(self.settings["snapshot_path_hash"])
-				myf.close()
-			else:
-				print "Setting snapshot autoresume point"
-				myf=open(self.settings["autoresume_path"]+"unpack_portage","w")
-				myf.write(self.settings["snapshot_path_hash"])
-				myf.close()
-
-			if "SNAPCACHE" in self.settings:
-				self.snapshot_lock_object.unlock()
-
-	def config_profile_link(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+\
-				"config_profile_link"):
-			print \
-				"Resume point detected, skipping config_profile_link operation..."
-		else:
-			# TODO: zmedico and I discussed making this a directory and pushing
-			# in a parent file, as well as other user-specified configuration.
-			print "Configuring profile link..."
-			cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.profile",\
-					"Error zapping profile link",env=self.env)
-			cmd("mkdir -p "+self.settings["chroot_path"]+"/etc/portage/")
-			cmd("ln -sf ../.." + self.settings["portdir"] + "/profiles/"+\
-				self.settings["target_profile"]+" "+\
-				self.settings["chroot_path"]+"/etc/portage/make.profile",\
-				"Error creating profile link",env=self.env)
-			touch(self.settings["autoresume_path"]+"config_profile_link")
-
-	def setup_confdir(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+\
-				"setup_confdir"):
-			print "Resume point detected, skipping setup_confdir operation..."
-		else:
-			if "portage_confdir" in self.settings:
-				print "Configuring /etc/portage..."
-				cmd("rsync -a "+self.settings["portage_confdir"]+"/ "+\
-					self.settings["chroot_path"]+"/etc/portage/",\
-					"Error copying /etc/portage",env=self.env)
-				touch(self.settings["autoresume_path"]+"setup_confdir")
-
-	def portage_overlay(self):
-		""" We copy the contents of our overlays to /usr/local/portage """
-		if "portage_overlay" in self.settings:
-			for x in self.settings["portage_overlay"]:
-				if os.path.exists(x):
-					print "Copying overlay dir " +x
-					cmd("mkdir -p "+self.settings["chroot_path"]+\
-						self.settings["local_overlay"],\
-						"Could not make portage_overlay dir",env=self.env)
-					cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+\
-						self.settings["local_overlay"],\
-						"Could not copy portage_overlay",env=self.env)
-
-	def root_overlay(self):
-		""" Copy over the root_overlay """
-		if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
-			for x in self.settings[self.settings["spec_prefix"]+\
-				"/root_overlay"]:
-				if os.path.exists(x):
-					print "Copying root_overlay: "+x
-					cmd("rsync -a "+x+"/ "+\
-						self.settings["chroot_path"],\
-						self.settings["spec_prefix"]+"/root_overlay: "+x+\
-						" copy failed.",env=self.env)
-
-	def base_dirs(self):
-		pass
-
-	def bind(self):
-		for x in self.mounts:
-			if not os.path.exists(self.settings["chroot_path"] + self.mountmap[x]):
-				os.makedirs(self.settings["chroot_path"]+x,0755)
-
-			if not os.path.exists(self.mountmap[x]):
-				if not self.mountmap[x] == "tmpfs":
-					os.makedirs(self.mountmap[x],0755)
-
-			src=self.mountmap[x]
-			if "SNAPCACHE" in self.settings and x == "/usr/portage":
-				self.snapshot_lock_object.read_lock()
-			if os.uname()[0] == "FreeBSD":
-				if src == "/dev":
-					retval=os.system("mount -t devfs none " +
-						self.settings["chroot_path"] + src)
-				else:
-					retval=os.system("mount_nullfs " + src + " " +
-						self.settings["chroot_path"] + src)
-			else:
-				if src == "tmpfs":
-					if "var_tmpfs_portage" in self.settings:
-						retval=os.system("mount -t tmpfs -o size="+\
-							self.settings["var_tmpfs_portage"]+"G "+src+" "+\
-							self.settings["chroot_path"]+x)
-				else:
-					retval=os.system("mount --bind " + src + " " +
-						self.settings["chroot_path"] + src)
-			if retval!=0:
-				self.unbind()
-				raise CatalystError,"Couldn't bind mount " + src
-
-	def unbind(self):
-		ouch=0
-		mypath=self.settings["chroot_path"]
-		myrevmounts=self.mounts[:]
-		myrevmounts.reverse()
-		""" Unmount in reverse order for nested bind-mounts """
-		for x in myrevmounts:
-			if not os.path.exists(mypath + self.mountmap[x]):
-				continue
-
-			if not ismount(mypath + self.mountmap[x]):
-				continue
-
-			retval=os.system("umount "+\
-				os.path.join(mypath, self.mountmap[x].lstrip(os.path.sep)))
-
-			if retval!=0:
-				warn("First attempt to unmount: " + mypath +
-					self.mountmap[x] +" failed.")
-				warn("Killing any pids still running in the chroot")
-
-				self.kill_chroot_pids()
-
-				retval2=os.system("umount " + mypath + self.mountmap[x])
-				if retval2!=0:
-					ouch=1
-					warn("Couldn't umount bind mount: " + mypath + self.mountmap[x])
-
-			if "SNAPCACHE" in self.settings and x == "/usr/portage":
-				try:
-					"""
-					It's possible the snapshot lock object isn't created yet.
-					This is because mount safety check calls unbind before the
-					target is fully initialized
-					"""
-					self.snapshot_lock_object.unlock()
-				except:
-					pass
-		if ouch:
-			"""
-			if any bind mounts really failed, then we need to raise
-			this to potentially prevent an upcoming bash stage cleanup script
-			from wiping our bind mounts.
-			"""
-			raise CatalystError,\
-				"Couldn't umount one or more bind-mounts; aborting for safety."
-
-	def chroot_setup(self):
-		self.makeconf=read_makeconf(self.settings["chroot_path"]+\
-			"/etc/portage/make.conf")
-		self.override_cbuild()
-		self.override_chost()
-		self.override_cflags()
-		self.override_cxxflags()
-		self.override_ldflags()
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"chroot_setup"):
-			print "Resume point detected, skipping chroot_setup operation..."
-		else:
-			print "Setting up chroot..."
-
-			#self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/portage/make.conf")
-
-			cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
-				"Could not copy resolv.conf into place.",env=self.env)
-
-			""" Copy over the envscript, if applicable """
-			if "ENVSCRIPT" in self.settings:
-				if not os.path.exists(self.settings["ENVSCRIPT"]):
-					raise CatalystError,\
-						"Can't find envscript "+self.settings["ENVSCRIPT"]
-
-				print "\nWarning!!!!"
-				print "\tOverriding certain env variables may cause catastrophic failure."
-				print "\tIf your build fails look here first as the possible problem."
-				print "\tCatalyst assumes you know what you are doing when setting"
-				print "\t\tthese variables."
-				print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
-				print "\tYou have been warned\n"
-
-				cmd("cp "+self.settings["ENVSCRIPT"]+" "+\
-					self.settings["chroot_path"]+"/tmp/envscript",\
-					"Could not copy envscript into place.",env=self.env)
-
-			"""
-			Copy over /etc/hosts from the host in case there are any
-			specialties in there
-			"""
-			if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
-				cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+\
-					self.settings["chroot_path"]+"/etc/hosts.catalyst",\
-					"Could not backup /etc/hosts",env=self.env)
-				cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts",\
-					"Could not copy /etc/hosts",env=self.env)
-
-			""" Modify and write out make.conf (for the chroot) """
-			cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.conf",\
-				"Could not remove "+self.settings["chroot_path"]+\
-				"/etc/portage/make.conf",env=self.env)
-			myf=open(self.settings["chroot_path"]+"/etc/portage/make.conf","w")
-			myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
-			myf.write("# Please consult /usr/share/portage/config/make.conf.example for a more\n# detailed example.\n")
-			if "CFLAGS" in self.settings:
-				myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
-			if "CXXFLAGS" in self.settings:
-				if self.settings["CXXFLAGS"]!=self.settings["CFLAGS"]:
-					myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
-				else:
-					myf.write('CXXFLAGS="${CFLAGS}"\n')
-			else:
-				myf.write('CXXFLAGS="${CFLAGS}"\n')
-
-			if "LDFLAGS" in self.settings:
-				myf.write("# LDFLAGS is unsupported.  USE AT YOUR OWN RISK!\n")
-				myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
-			if "CBUILD" in self.settings:
-				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")
-				myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
-
-			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")
-			myf.write('CHOST="'+self.settings["CHOST"]+'"\n')
-
-			""" Figure out what our USE vars are for building """
-			myusevars=[]
-			if "HOSTUSE" in self.settings:
-				myusevars.extend(self.settings["HOSTUSE"])
-
-			if "use" in self.settings:
-				myusevars.extend(self.settings["use"])
-
-			if myusevars:
-				myf.write("# These are the USE flags that were used in addition to what is provided by the\n# profile used for building.\n")
-				myusevars = sorted(set(myusevars))
-				myf.write('USE="'+string.join(myusevars)+'"\n')
-				if '-*' in myusevars:
-					print "\nWarning!!!  "
-					print "\tThe use of -* in "+self.settings["spec_prefix"]+\
-						"/use will cause portage to ignore"
-					print "\tpackage.use in the profile and portage_confdir. You've been warned!"
-
-			myf.write('PORTDIR="%s"\n' % self.settings['portdir'])
-			myf.write('DISTDIR="%s"\n' % self.settings['distdir'])
-			myf.write('PKGDIR="%s"\n' % self.settings['packagedir'])
-
-			""" Setup the portage overlay """
-			if "portage_overlay" in self.settings:
-				myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
-
-			myf.close()
-			cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
-				self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
-				"Could not backup /etc/portage/make.conf",env=self.env)
-			touch(self.settings["autoresume_path"]+"chroot_setup")
-
-	def fsscript(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
-			print "Resume point detected, skipping fsscript operation..."
-		else:
-			if "fsscript" in self.settings:
-				if os.path.exists(self.settings["controller_file"]):
-					cmd("/bin/bash "+self.settings["controller_file"]+\
-						" fsscript","fsscript script failed.",env=self.env)
-					touch(self.settings["autoresume_path"]+"fsscript")
-
-	def rcupdate(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
-			print "Resume point detected, skipping rcupdate operation..."
-		else:
-			if os.path.exists(self.settings["controller_file"]):
-				cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
-					"rc-update script failed.",env=self.env)
-				touch(self.settings["autoresume_path"]+"rcupdate")
-
-	def clean(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"clean"):
-			print "Resume point detected, skipping clean operation..."
-		else:
-			for x in self.settings["cleanables"]:
-				print "Cleaning chroot: "+x+"... "
-				cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
-					x,env=self.env)
-
-		""" Put /etc/hosts back into place """
-		if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
-			cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
-				self.settings["chroot_path"]+"/etc/hosts",\
-				"Could not replace /etc/hosts",env=self.env)
-
-		""" Remove our overlay """
-		if os.path.exists(self.settings["chroot_path"] + self.settings["local_overlay"]):
-			cmd("rm -rf " + self.settings["chroot_path"] + self.settings["local_overlay"],
-				"Could not remove " + self.settings["local_overlay"], env=self.env)
-			cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
-				"/etc/portage/make.conf",\
-				"Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
-
-		""" Clean up old and obsoleted files in /etc """
-		if os.path.exists(self.settings["stage_path"]+"/etc"):
-			cmd("find "+self.settings["stage_path"]+\
-				"/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
-				"Could not remove stray files in /etc",env=self.env)
-
-		if os.path.exists(self.settings["controller_file"]):
-			cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
-				"clean script failed.",env=self.env)
-			touch(self.settings["autoresume_path"]+"clean")
-
-	def empty(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"empty"):
-			print "Resume point detected, skipping empty operation..."
-		else:
-			if self.settings["spec_prefix"]+"/empty" in self.settings:
-				if type(self.settings[self.settings["spec_prefix"]+\
-					"/empty"])==types.StringType:
-					self.settings[self.settings["spec_prefix"]+"/empty"]=\
-						self.settings[self.settings["spec_prefix"]+\
-						"/empty"].split()
-				for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
-					myemp=self.settings["destpath"]+x
-					if not os.path.isdir(myemp) or os.path.islink(myemp):
-						print x,"not a directory or does not exist, skipping 'empty' operation."
-						continue
-					print "Emptying directory",x
-					"""
-					stat the dir, delete the dir, recreate the dir and set
-					the proper perms and ownership
-					"""
-					mystat=os.stat(myemp)
-					shutil.rmtree(myemp)
-					os.makedirs(myemp,0755)
-					os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
-					os.chmod(myemp,mystat[ST_MODE])
-			touch(self.settings["autoresume_path"]+"empty")
-
-	def remove(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"remove"):
-			print "Resume point detected, skipping remove operation..."
-		else:
-			if self.settings["spec_prefix"]+"/rm" in self.settings:
-				for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
-					"""
-					We're going to shell out for all these cleaning
-					operations, so we get easy glob handling.
-					"""
-					print "livecd: removing "+x
-					os.system("rm -rf "+self.settings["chroot_path"]+x)
-				try:
-					if os.path.exists(self.settings["controller_file"]):
-						cmd("/bin/bash "+self.settings["controller_file"]+\
-							" clean","Clean  failed.",env=self.env)
-						touch(self.settings["autoresume_path"]+"remove")
-				except:
-					self.unbind()
-					raise
-
-	def preclean(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"preclean"):
-			print "Resume point detected, skipping preclean operation..."
-		else:
-			try:
-				if os.path.exists(self.settings["controller_file"]):
-					cmd("/bin/bash "+self.settings["controller_file"]+\
-						" preclean","preclean script failed.",env=self.env)
-					touch(self.settings["autoresume_path"]+"preclean")
-
-			except:
-				self.unbind()
-				raise CatalystError, "Build failed, could not execute preclean"
-
-	def capture(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"capture"):
-			print "Resume point detected, skipping capture operation..."
-		else:
-			""" Capture target in a tarball """
-			mypath=self.settings["target_path"].split("/")
-			""" Remove filename from path """
-			mypath=string.join(mypath[:-1],"/")
-
-			""" Now make sure path exists """
-			if not os.path.exists(mypath):
-				os.makedirs(mypath)
-
-			print "Creating stage tarball..."
-
-			cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
-				self.settings["stage_path"]+" .",\
-				"Couldn't create stage tarball",env=self.env)
-
-			self.gen_contents_file(self.settings["target_path"])
-			self.gen_digest_file(self.settings["target_path"])
-
-			touch(self.settings["autoresume_path"]+"capture")
-
-	def run_local(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"run_local"):
-			print "Resume point detected, skipping run_local operation..."
-		else:
-			try:
-				if os.path.exists(self.settings["controller_file"]):
-					cmd("/bin/bash "+self.settings["controller_file"]+" run",\
-						"run script failed.",env=self.env)
-					touch(self.settings["autoresume_path"]+"run_local")
-
-			except CatalystError:
-				self.unbind()
-				raise CatalystError,"Stage build aborting due to error."
-
-	def setup_environment(self):
-		"""
-		Modify the current environment. This is an ugly hack that should be
-		fixed. We need this to use the os.system() call since we can't
-		specify our own environ
-		"""
-		for x in self.settings.keys():
-			""" Sanitize var names by doing "s|/-.|_|g" """
-			varname="clst_"+string.replace(x,"/","_")
-			varname=string.replace(varname,"-","_")
-			varname=string.replace(varname,".","_")
-			if type(self.settings[x])==types.StringType:
-				""" Prefix to prevent namespace clashes """
-				#os.environ[varname]=self.settings[x]
-				self.env[varname]=self.settings[x]
-			elif type(self.settings[x])==types.ListType:
-				#os.environ[varname]=string.join(self.settings[x])
-				self.env[varname]=string.join(self.settings[x])
-			elif type(self.settings[x])==types.BooleanType:
-				if self.settings[x]:
-					self.env[varname]="true"
-				else:
-					self.env[varname]="false"
-		if "makeopts" in self.settings:
-			self.env["MAKEOPTS"]=self.settings["makeopts"]
-
-	def run(self):
-		self.chroot_lock.write_lock()
-
-		""" Kill any pids in the chroot "" """
-		self.kill_chroot_pids()
-
-		""" Check for mounts right away and abort if we cannot unmount them """
-		self.mount_safety_check()
-
-		if "CLEAR_AUTORESUME" in self.settings:
-			self.clear_autoresume()
-
-		if "PURGETMPONLY" in self.settings:
-			self.purge()
-			return
-
-		if "PURGEONLY" in self.settings:
-			self.purge()
-			return
-
-		if "PURGE" in self.settings:
-			self.purge()
-
-		for x in self.settings["action_sequence"]:
-			print "--- Running action sequence: "+x
-			sys.stdout.flush()
-			try:
-				apply(getattr(self,x))
-			except:
-				self.mount_safety_check()
-				raise
-
-		self.chroot_lock.unlock()
-
-	def unmerge(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
-			print "Resume point detected, skipping unmerge operation..."
-		else:
-			if self.settings["spec_prefix"]+"/unmerge" in self.settings:
-				if type(self.settings[self.settings["spec_prefix"]+\
-					"/unmerge"])==types.StringType:
-					self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
-						[self.settings[self.settings["spec_prefix"]+"/unmerge"]]
-				myunmerge=\
-					self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
-
-				for x in range(0,len(myunmerge)):
-					"""
-					Surround args with quotes for passing to bash, allows
-					things like "<" to remain intact
-					"""
-					myunmerge[x]="'"+myunmerge[x]+"'"
-				myunmerge=string.join(myunmerge)
-
-				""" Before cleaning, unmerge stuff """
-				try:
-					cmd("/bin/bash "+self.settings["controller_file"]+\
-						" unmerge "+ myunmerge,"Unmerge script failed.",\
-						env=self.env)
-					print "unmerge shell script"
-				except CatalystError:
-					self.unbind()
-					raise
-				touch(self.settings["autoresume_path"]+"unmerge")
-
-	def target_setup(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
-			print "Resume point detected, skipping target_setup operation..."
-		else:
-			print "Setting up filesystems per filesystem type"
-			cmd("/bin/bash "+self.settings["controller_file"]+\
-				" target_image_setup "+ self.settings["target_path"],\
-				"target_image_setup script failed.",env=self.env)
-			touch(self.settings["autoresume_path"]+"target_setup")
-
-	def setup_overlay(self):
-		if "AUTORESUME" in self.settings \
-		and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
-			print "Resume point detected, skipping setup_overlay operation..."
-		else:
-			if self.settings["spec_prefix"]+"/overlay" in self.settings:
-				for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
-					if os.path.exists(x):
-						cmd("rsync -a "+x+"/ "+\
-							self.settings["target_path"],\
-							self.settings["spec_prefix"]+"overlay: "+x+\
-							" copy failed.",env=self.env)
-				touch(self.settings["autoresume_path"]+"setup_overlay")
-
-	def create_iso(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
-			print "Resume point detected, skipping create_iso operation..."
-		else:
-			""" Create the ISO """
-			if "iso" in self.settings:
-				cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
-					self.settings["iso"],"ISO creation script failed.",\
-					env=self.env)
-				self.gen_contents_file(self.settings["iso"])
-				self.gen_digest_file(self.settings["iso"])
-				touch(self.settings["autoresume_path"]+"create_iso")
-			else:
-				print "WARNING: livecd/iso was not defined."
-				print "An ISO Image will not be created."
-
-	def build_packages(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+\
-				"build_packages"):
-			print "Resume point detected, skipping build_packages operation..."
-		else:
-			if self.settings["spec_prefix"]+"/packages" in self.settings:
-				if "AUTORESUME" in self.settings \
-					and os.path.exists(self.settings["autoresume_path"]+\
-						"build_packages"):
-					print "Resume point detected, skipping build_packages operation..."
-				else:
-					mypack=\
-						list_bashify(self.settings[self.settings["spec_prefix"]\
-						+"/packages"])
-					try:
-						cmd("/bin/bash "+self.settings["controller_file"]+\
-							" build_packages "+mypack,\
-							"Error in attempt to build packages",env=self.env)
-						touch(self.settings["autoresume_path"]+"build_packages")
-					except CatalystError:
-						self.unbind()
-						raise CatalystError,self.settings["spec_prefix"]+\
-							"build aborting due to error."
-
-	def build_kernel(self):
-		"Build all configured kernels"
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
-			print "Resume point detected, skipping build_kernel operation..."
-		else:
-			if "boot/kernel" in self.settings:
-				try:
-					mynames=self.settings["boot/kernel"]
-					if type(mynames)==types.StringType:
-						mynames=[mynames]
-					"""
-					Execute the script that sets up the kernel build environment
-					"""
-					cmd("/bin/bash "+self.settings["controller_file"]+\
-						" pre-kmerge ","Runscript pre-kmerge failed",\
-						env=self.env)
-					for kname in mynames:
-						self._build_kernel(kname=kname)
-					touch(self.settings["autoresume_path"]+"build_kernel")
-				except CatalystError:
-					self.unbind()
-					raise CatalystError,\
-						"build aborting due to kernel build error."
-
-	def _build_kernel(self, kname):
-		"Build a single configured kernel by name"
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]\
-				+"build_kernel_"+kname):
-			print "Resume point detected, skipping build_kernel for "+kname+" operation..."
-			return
-		self._copy_kernel_config(kname=kname)
-
-		"""
-		If we need to pass special options to the bootloader
-		for this kernel put them into the environment
-		"""
-		if "boot/kernel/"+kname+"/kernelopts" in self.settings:
-			myopts=self.settings["boot/kernel/"+kname+\
-				"/kernelopts"]
-
-			if type(myopts) != types.StringType:
-				myopts = string.join(myopts)
-				self.env[kname+"_kernelopts"]=myopts
-
-			else:
-				self.env[kname+"_kernelopts"]=""
-
-		if "boot/kernel/"+kname+"/extraversion" not in self.settings:
-			self.settings["boot/kernel/"+kname+\
-				"/extraversion"]=""
-
-		self.env["clst_kextraversion"]=\
-			self.settings["boot/kernel/"+kname+\
-			"/extraversion"]
-
-		self._copy_initramfs_overlay(kname=kname)
-
-		""" Execute the script that builds the kernel """
-		cmd("/bin/bash "+self.settings["controller_file"]+\
-			" kernel "+kname,\
-			"Runscript kernel build failed",env=self.env)
-
-		if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
-			if os.path.exists(self.settings["chroot_path"]+\
-				"/tmp/initramfs_overlay/"):
-				print "Cleaning up temporary overlay dir"
-				cmd("rm -R "+self.settings["chroot_path"]+\
-					"/tmp/initramfs_overlay/",env=self.env)
-
-		touch(self.settings["autoresume_path"]+\
-			"build_kernel_"+kname)
-
-		"""
-		Execute the script that cleans up the kernel build
-		environment
-		"""
-		cmd("/bin/bash "+self.settings["controller_file"]+\
-			" post-kmerge ",
-			"Runscript post-kmerge failed",env=self.env)
-
-	def _copy_kernel_config(self, kname):
-		if "boot/kernel/"+kname+"/config" in self.settings:
-			if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
-				self.unbind()
-				raise CatalystError,\
-					"Can't find kernel config: "+\
-					self.settings["boot/kernel/"+kname+\
-					"/config"]
-
-			try:
-				cmd("cp "+self.settings["boot/kernel/"+kname+\
-					"/config"]+" "+\
-					self.settings["chroot_path"]+"/var/tmp/"+\
-					kname+".config",\
-					"Couldn't copy kernel config: "+\
-					self.settings["boot/kernel/"+kname+\
-					"/config"],env=self.env)
-
-			except CatalystError:
-				self.unbind()
-
-	def _copy_initramfs_overlay(self, kname):
-		if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
-			if os.path.exists(self.settings["boot/kernel/"+\
-				kname+"/initramfs_overlay"]):
-				print "Copying initramfs_overlay dir "+\
-					self.settings["boot/kernel/"+kname+\
-					"/initramfs_overlay"]
-
-				cmd("mkdir -p "+\
-					self.settings["chroot_path"]+\
-					"/tmp/initramfs_overlay/"+\
-					self.settings["boot/kernel/"+kname+\
-					"/initramfs_overlay"],env=self.env)
-
-				cmd("cp -R "+self.settings["boot/kernel/"+\
-					kname+"/initramfs_overlay"]+"/* "+\
-					self.settings["chroot_path"]+\
-					"/tmp/initramfs_overlay/"+\
-					self.settings["boot/kernel/"+kname+\
-					"/initramfs_overlay"],env=self.env)
-
-	def bootloader(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
-			print "Resume point detected, skipping bootloader operation..."
-		else:
-			try:
-				cmd("/bin/bash "+self.settings["controller_file"]+\
-					" bootloader " + self.settings["target_path"],\
-					"Bootloader script failed.",env=self.env)
-				touch(self.settings["autoresume_path"]+"bootloader")
-			except CatalystError:
-				self.unbind()
-				raise CatalystError,"Script aborting due to error."
-
-	def livecd_update(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+\
-				"livecd_update"):
-			print "Resume point detected, skipping build_packages operation..."
-		else:
-			try:
-				cmd("/bin/bash "+self.settings["controller_file"]+\
-					" livecd-update","livecd-update failed.",env=self.env)
-				touch(self.settings["autoresume_path"]+"livecd_update")
-
-			except CatalystError:
-				self.unbind()
-				raise CatalystError,"build aborting due to livecd_update error."
-
-	def clear_chroot(self):
-		myemp=self.settings["chroot_path"]
-		if os.path.isdir(myemp):
-			print "Emptying directory",myemp
-			"""
-			stat the dir, delete the dir, recreate the dir and set
-			the proper perms and ownership
-			"""
-			mystat=os.stat(myemp)
-			#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
-			""" There's no easy way to change flags recursively in python """
-			if os.uname()[0] == "FreeBSD":
-				os.system("chflags -R noschg "+myemp)
-			shutil.rmtree(myemp)
-			os.makedirs(myemp,0755)
-			os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
-			os.chmod(myemp,mystat[ST_MODE])
-
-	def clear_packages(self):
-		if "PKGCACHE" in self.settings:
-			print "purging the pkgcache ..."
-
-			myemp=self.settings["pkgcache_path"]
-			if os.path.isdir(myemp):
-				print "Emptying directory",myemp
-				"""
-				stat the dir, delete the dir, recreate the dir and set
-				the proper perms and ownership
-				"""
-				mystat=os.stat(myemp)
-				#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
-				shutil.rmtree(myemp)
-				os.makedirs(myemp,0755)
-				os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
-				os.chmod(myemp,mystat[ST_MODE])
-
-	def clear_kerncache(self):
-		if "KERNCACHE" in self.settings:
-			print "purging the kerncache ..."
-
-			myemp=self.settings["kerncache_path"]
-			if os.path.isdir(myemp):
-				print "Emptying directory",myemp
-				"""
-				stat the dir, delete the dir, recreate the dir and set
-				the proper perms and ownership
-				"""
-				mystat=os.stat(myemp)
-				#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
-				shutil.rmtree(myemp)
-				os.makedirs(myemp,0755)
-				os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
-				os.chmod(myemp,mystat[ST_MODE])
-
-	def clear_autoresume(self):
-		""" Clean resume points since they are no longer needed """
-		if "AUTORESUME" in self.settings:
-			print "Removing AutoResume Points: ..."
-		myemp=self.settings["autoresume_path"]
-		if os.path.isdir(myemp):
-				if "AUTORESUME" in self.settings:
-					print "Emptying directory",myemp
-				"""
-				stat the dir, delete the dir, recreate the dir and set
-				the proper perms and ownership
-				"""
-				mystat=os.stat(myemp)
-				if os.uname()[0] == "FreeBSD":
-					cmd("chflags -R noschg "+myemp,\
-						"Could not remove immutable flag for file "\
-						+myemp)
-				#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
-				shutil.rmtree(myemp)
-				os.makedirs(myemp,0755)
-				os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
-				os.chmod(myemp,mystat[ST_MODE])
-
-	def gen_contents_file(self,file):
-		if os.path.exists(file+".CONTENTS"):
-			os.remove(file+".CONTENTS")
-		if "contents" in self.settings:
-			if os.path.exists(file):
-				myf=open(file+".CONTENTS","w")
-				keys={}
-				for i in self.settings["contents"].split():
-					keys[i]=1
-					array=keys.keys()
-					array.sort()
-				for j in array:
-					contents=generate_contents(file,contents_function=j,\
-						verbose="VERBOSE" in self.settings)
-					if contents:
-						myf.write(contents)
-				myf.close()
-
-	def gen_digest_file(self,file):
-		if os.path.exists(file+".DIGESTS"):
-			os.remove(file+".DIGESTS")
-		if "digests" in self.settings:
-			if os.path.exists(file):
-				myf=open(file+".DIGESTS","w")
-				keys={}
-				for i in self.settings["digests"].split():
-					keys[i]=1
-					array=keys.keys()
-					array.sort()
-				for f in [file, file+'.CONTENTS']:
-					if os.path.exists(f):
-						if "all" in array:
-							for k in hash_map.keys():
-								hash=generate_hash(f,hash_function=k,verbose=\
-									"VERBOSE" in self.settings)
-								myf.write(hash)
-						else:
-							for j in array:
-								hash=generate_hash(f,hash_function=j,verbose=\
-									"VERBOSE" in self.settings)
-								myf.write(hash)
-				myf.close()
-
-	def purge(self):
-		countdown(10,"Purging Caches ...")
-		if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
-			print "clearing autoresume ..."
-			self.clear_autoresume()
-
-			print "clearing chroot ..."
-			self.clear_chroot()
-
-			if "PURGETMPONLY" not in self.settings:
-				print "clearing package cache ..."
-				self.clear_packages()
-
-			print "clearing kerncache ..."
-			self.clear_kerncache()
-
-# vim: ts=4 sw=4 sta et sts=4 ai
diff --git a/catalyst/modules/generic_target.py b/catalyst/modules/generic_target.py
deleted file mode 100644
index de51994..0000000
--- a/catalyst/modules/generic_target.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from catalyst.support import *
-
-class generic_target:
-	"""
-	The toplevel class for generic_stage_target. This is about as generic as we get.
-	"""
-	def __init__(self,myspec,addlargs):
-		addl_arg_parse(myspec,addlargs,self.required_values,self.valid_values)
-		self.settings=myspec
-		self.env={}
-		self.env["PATH"]="/bin:/sbin:/usr/bin:/usr/sbin"
diff --git a/catalyst/modules/grp_target.py b/catalyst/modules/grp_target.py
deleted file mode 100644
index 8e70042..0000000
--- a/catalyst/modules/grp_target.py
+++ /dev/null
@@ -1,118 +0,0 @@
-"""
-Gentoo Reference Platform (GRP) target
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-import os,types,glob
-from catalyst.support import *
-from generic_stage_target import *
-
-class grp_target(generic_stage_target):
-	"""
-	The builder class for GRP (Gentoo Reference Platform) builds.
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=["version_stamp","target","subarch",\
-			"rel_type","profile","snapshot","source_subpath"]
-
-		self.valid_values=self.required_values[:]
-		self.valid_values.extend(["grp/use"])
-		if "grp" not in addlargs:
-			raise CatalystError,"Required value \"grp\" not specified in spec."
-
-		self.required_values.extend(["grp"])
-		if type(addlargs["grp"])==types.StringType:
-			addlargs["grp"]=[addlargs["grp"]]
-
-		if "grp/use" in addlargs:
-			if type(addlargs["grp/use"])==types.StringType:
-				addlargs["grp/use"]=[addlargs["grp/use"]]
-
-		for x in addlargs["grp"]:
-			self.required_values.append("grp/"+x+"/packages")
-			self.required_values.append("grp/"+x+"/type")
-
-		generic_stage_target.__init__(self,spec,addlargs)
-
-	def set_target_path(self):
-		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["target_subpath"]+"/")
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
-			print "Resume point detected, skipping target path setup operation..."
-		else:
-			# first clean up any existing target stuff
-			#if os.path.isdir(self.settings["target_path"]):
-				#cmd("rm -rf "+self.settings["target_path"],
-				#"Could not remove existing directory: "+self.settings["target_path"],env=self.env)
-			if not os.path.exists(self.settings["target_path"]):
-				os.makedirs(self.settings["target_path"])
-
-			touch(self.settings["autoresume_path"]+"setup_target_path")
-
-	def run_local(self):
-		for pkgset in self.settings["grp"]:
-			# example call: "grp.sh run pkgset cd1 xmms vim sys-apps/gleep"
-			mypackages=list_bashify(self.settings["grp/"+pkgset+"/packages"])
-			try:
-				cmd("/bin/bash "+self.settings["controller_file"]+" run "+self.settings["grp/"+pkgset+"/type"]\
-					+" "+pkgset+" "+mypackages,env=self.env)
-
-			except CatalystError:
-				self.unbind()
-				raise CatalystError,"GRP build aborting due to error."
-
-	def set_use(self):
-		generic_stage_target.set_use(self)
-		if "BINDIST" in self.settings:
-			if "use" in self.settings:
-				self.settings["use"].append("bindist")
-			else:
-				self.settings["use"]=["bindist"]
-
-	def set_mounts(self):
-	    self.mounts.append("/tmp/grp")
-            self.mountmap["/tmp/grp"]=self.settings["target_path"]
-
-	def generate_digests(self):
-		for pkgset in self.settings["grp"]:
-			if self.settings["grp/"+pkgset+"/type"] == "pkgset":
-				destdir=normpath(self.settings["target_path"]+"/"+pkgset+"/All")
-				print "Digesting files in the pkgset....."
-				digests=glob.glob(destdir+'/*.DIGESTS')
-				for i in digests:
-					if os.path.exists(i):
-						os.remove(i)
-
-				files=os.listdir(destdir)
-				#ignore files starting with '.' using list comprehension
-				files=[filename for filename in files if filename[0] != '.']
-				for i in files:
-					if os.path.isfile(normpath(destdir+"/"+i)):
-						self.gen_contents_file(normpath(destdir+"/"+i))
-						self.gen_digest_file(normpath(destdir+"/"+i))
-			else:
-				destdir=normpath(self.settings["target_path"]+"/"+pkgset)
-				print "Digesting files in the srcset....."
-
-				digests=glob.glob(destdir+'/*.DIGESTS')
-				for i in digests:
-					if os.path.exists(i):
-						os.remove(i)
-
-				files=os.listdir(destdir)
-				#ignore files starting with '.' using list comprehension
-				files=[filename for filename in files if filename[0] != '.']
-				for i in files:
-					if os.path.isfile(normpath(destdir+"/"+i)):
-						#self.gen_contents_file(normpath(destdir+"/"+i))
-						self.gen_digest_file(normpath(destdir+"/"+i))
-
-	def set_action_sequence(self):
-	    self.settings["action_sequence"]=["unpack","unpack_snapshot",\
-					"config_profile_link","setup_confdir","portage_overlay","bind","chroot_setup",\
-					"setup_environment","run_local","unbind",\
-					"generate_digests","clear_autoresume"]
-
-def register(foo):
-	foo.update({"grp":grp_target})
-	return foo
diff --git a/catalyst/modules/livecd_stage1_target.py b/catalyst/modules/livecd_stage1_target.py
deleted file mode 100644
index ac846ec..0000000
--- a/catalyst/modules/livecd_stage1_target.py
+++ /dev/null
@@ -1,75 +0,0 @@
-"""
-LiveCD stage1 target
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-from catalyst.support import *
-from generic_stage_target import *
-
-class livecd_stage1_target(generic_stage_target):
-	"""
-	Builder class for LiveCD stage1.
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=["livecd/packages"]
-		self.valid_values=self.required_values[:]
-
-		self.valid_values.extend(["livecd/use"])
-		generic_stage_target.__init__(self,spec,addlargs)
-
-	def set_action_sequence(self):
-		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
-					"config_profile_link","setup_confdir","portage_overlay",\
-					"bind","chroot_setup","setup_environment","build_packages",\
-					"unbind", "clean","clear_autoresume"]
-
-	def set_target_path(self):
-		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["target_subpath"])
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
-				print "Resume point detected, skipping target path setup operation..."
-		else:
-			# first clean up any existing target stuff
-			if os.path.exists(self.settings["target_path"]):
-				cmd("rm -rf "+self.settings["target_path"],\
-					"Could not remove existing directory: "+self.settings["target_path"],env=self.env)
-				touch(self.settings["autoresume_path"]+"setup_target_path")
-
-			if not os.path.exists(self.settings["target_path"]):
-				os.makedirs(self.settings["target_path"])
-
-	def set_target_path(self):
-		pass
-
-	def set_spec_prefix(self):
-	                self.settings["spec_prefix"]="livecd"
-
-	def set_use(self):
-		generic_stage_target.set_use(self)
-		if "use" in self.settings:
-			self.settings["use"].append("livecd")
-			if "BINDIST" in self.settings:
-				self.settings["use"].append("bindist")
-		else:
-			self.settings["use"]=["livecd"]
-			if "BINDIST" in self.settings:
-				self.settings["use"].append("bindist")
-
-	def set_packages(self):
-		generic_stage_target.set_packages(self)
-		if self.settings["spec_prefix"]+"/packages" in self.settings:
-			if type(self.settings[self.settings["spec_prefix"]+"/packages"]) == types.StringType:
-				self.settings[self.settings["spec_prefix"]+"/packages"] = \
-					self.settings[self.settings["spec_prefix"]+"/packages"].split()
-		self.settings[self.settings["spec_prefix"]+"/packages"].append("app-misc/livecd-tools")
-
-	def set_pkgcache_path(self):
-		if "pkgcache_path" in self.settings:
-			if type(self.settings["pkgcache_path"]) != types.StringType:
-				self.settings["pkgcache_path"]=normpath(string.join(self.settings["pkgcache_path"]))
-		else:
-			generic_stage_target.set_pkgcache_path(self)
-
-def register(foo):
-	foo.update({"livecd-stage1":livecd_stage1_target})
-	return foo
diff --git a/catalyst/modules/livecd_stage2_target.py b/catalyst/modules/livecd_stage2_target.py
deleted file mode 100644
index 1bfd820..0000000
--- a/catalyst/modules/livecd_stage2_target.py
+++ /dev/null
@@ -1,146 +0,0 @@
-"""
-LiveCD stage2 target, builds upon previous LiveCD stage1 tarball
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-import os,string,types,stat,shutil
-from catalyst.support import *
-from generic_stage_target import *
-
-class livecd_stage2_target(generic_stage_target):
-	"""
-	Builder class for a LiveCD stage2 build.
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=["boot/kernel"]
-
-		self.valid_values=[]
-
-		self.valid_values.extend(self.required_values)
-		self.valid_values.extend(["livecd/cdtar","livecd/empty","livecd/rm",\
-			"livecd/unmerge","livecd/iso","livecd/gk_mainargs","livecd/type",\
-			"livecd/readme","livecd/motd","livecd/overlay",\
-			"livecd/modblacklist","livecd/splash_theme","livecd/rcadd",\
-			"livecd/rcdel","livecd/fsscript","livecd/xinitrc",\
-			"livecd/root_overlay","livecd/users","portage_overlay",\
-			"livecd/fstype","livecd/fsops","livecd/linuxrc","livecd/bootargs",\
-			"gamecd/conf","livecd/xdm","livecd/xsession","livecd/volid"])
-
-		generic_stage_target.__init__(self,spec,addlargs)
-		if "livecd/type" not in self.settings:
-			self.settings["livecd/type"] = "generic-livecd"
-
-		file_locate(self.settings, ["cdtar","controller_file"])
-
-	def set_source_path(self):
-		self.settings["source_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2")
-		if os.path.isfile(self.settings["source_path"]):
-			self.settings["source_path_hash"]=generate_hash(self.settings["source_path"])
-		else:
-			self.settings["source_path"]=normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/")
-		if not os.path.exists(self.settings["source_path"]):
-			raise CatalystError,"Source Path: "+self.settings["source_path"]+" does not exist."
-
-	def set_spec_prefix(self):
-	    self.settings["spec_prefix"]="livecd"
-
-	def set_target_path(self):
-		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["target_subpath"]+"/")
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
-				print "Resume point detected, skipping target path setup operation..."
-		else:
-			# first clean up any existing target stuff
-			if os.path.isdir(self.settings["target_path"]):
-				cmd("rm -rf "+self.settings["target_path"],
-				"Could not remove existing directory: "+self.settings["target_path"],env=self.env)
-				touch(self.settings["autoresume_path"]+"setup_target_path")
-			if not os.path.exists(self.settings["target_path"]):
-				os.makedirs(self.settings["target_path"])
-
-	def run_local(self):
-		# what modules do we want to blacklist?
-		if "livecd/modblacklist" in self.settings:
-			try:
-				myf=open(self.settings["chroot_path"]+"/etc/modprobe.d/blacklist.conf","a")
-			except:
-				self.unbind()
-				raise CatalystError,"Couldn't open "+self.settings["chroot_path"]+"/etc/modprobe.d/blacklist.conf."
-
-			myf.write("\n#Added by Catalyst:")
-			# workaround until config.py is using configparser
-			if isinstance(self.settings["livecd/modblacklist"], str):
-				self.settings["livecd/modblacklist"] = self.settings["livecd/modblacklist"].split()
-			for x in self.settings["livecd/modblacklist"]:
-				myf.write("\nblacklist "+x)
-			myf.close()
-
-	def unpack(self):
-		unpack=True
-		display_msg=None
-
-		clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+"unpack")
-
-		if os.path.isdir(self.settings["source_path"]):
-			unpack_cmd="rsync -a --delete "+self.settings["source_path"]+" "+self.settings["chroot_path"]
-			display_msg="\nStarting rsync from "+self.settings["source_path"]+"\nto "+\
-				self.settings["chroot_path"]+" (This may take some time) ...\n"
-			error_msg="Rsync of "+self.settings["source_path"]+" to "+self.settings["chroot_path"]+" failed."
-			invalid_snapshot=False
-
-		if "AUTORESUME" in self.settings:
-			if os.path.isdir(self.settings["source_path"]) and \
-				os.path.exists(self.settings["autoresume_path"]+"unpack"):
-				print "Resume point detected, skipping unpack operation..."
-				unpack=False
-			elif "source_path_hash" in self.settings:
-				if self.settings["source_path_hash"] != clst_unpack_hash:
-					invalid_snapshot=True
-
-		if unpack:
-			self.mount_safety_check()
-			if invalid_snapshot:
-				print "No Valid Resume point detected, cleaning up  ..."
-				#os.remove(self.settings["autoresume_path"]+"dir_setup")
-				self.clear_autoresume()
-				self.clear_chroot()
-				#self.dir_setup()
-
-			if not os.path.exists(self.settings["chroot_path"]):
-				os.makedirs(self.settings["chroot_path"])
-
-			if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
-				os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
-
-			if "PKGCACHE" in self.settings:
-				if not os.path.exists(self.settings["pkgcache_path"]):
-					os.makedirs(self.settings["pkgcache_path"],0755)
-
-			if not display_msg:
-				raise CatalystError,"Could not find appropriate source. Please check the 'source_subpath' setting in the spec file."
-
-			print display_msg
-			cmd(unpack_cmd,error_msg,env=self.env)
-
-			if "source_path_hash" in self.settings:
-				myf=open(self.settings["autoresume_path"]+"unpack","w")
-				myf.write(self.settings["source_path_hash"])
-				myf.close()
-			else:
-				touch(self.settings["autoresume_path"]+"unpack")
-
-	def set_action_sequence(self):
-		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
-				"config_profile_link","setup_confdir","portage_overlay",\
-				"bind","chroot_setup","setup_environment","run_local",\
-				"build_kernel"]
-		if "FETCH" not in self.settings:
-			self.settings["action_sequence"] += ["bootloader","preclean",\
-				"livecd_update","root_overlay","fsscript","rcupdate","unmerge",\
-				"unbind","remove","empty","target_setup",\
-				"setup_overlay","create_iso"]
-		self.settings["action_sequence"].append("clear_autoresume")
-
-def register(foo):
-	foo.update({"livecd-stage2":livecd_stage2_target})
-	return foo
diff --git a/catalyst/modules/netboot2_target.py b/catalyst/modules/netboot2_target.py
deleted file mode 100644
index 2b3cd20..0000000
--- a/catalyst/modules/netboot2_target.py
+++ /dev/null
@@ -1,166 +0,0 @@
-"""
-netboot target, version 2
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-import os,string,types
-from catalyst.support import *
-from generic_stage_target import *
-
-class netboot2_target(generic_stage_target):
-	"""
-	Builder class for a netboot build, version 2
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=[
-			"boot/kernel"
-		]
-		self.valid_values=self.required_values[:]
-		self.valid_values.extend([
-			"netboot2/packages",
-			"netboot2/use",
-			"netboot2/extra_files",
-			"netboot2/overlay",
-			"netboot2/busybox_config",
-			"netboot2/root_overlay",
-			"netboot2/linuxrc"
-		])
-
-		try:
-			if "netboot2/packages" in addlargs:
-				if type(addlargs["netboot2/packages"]) == types.StringType:
-					loopy=[addlargs["netboot2/packages"]]
-				else:
-					loopy=addlargs["netboot2/packages"]
-
-				for x in loopy:
-					self.valid_values.append("netboot2/packages/"+x+"/files")
-		except:
-			raise CatalystError,"configuration error in netboot2/packages."
-
-		generic_stage_target.__init__(self,spec,addlargs)
-		self.set_build_kernel_vars()
-		self.settings["merge_path"]=normpath("/tmp/image/")
-
-	def set_target_path(self):
-		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+\
-			self.settings["target_subpath"]+"/")
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
-				print "Resume point detected, skipping target path setup operation..."
-		else:
-			# first clean up any existing target stuff
-			if os.path.isfile(self.settings["target_path"]):
-				cmd("rm -f "+self.settings["target_path"], \
-					"Could not remove existing file: "+self.settings["target_path"],env=self.env)
-				touch(self.settings["autoresume_path"]+"setup_target_path")
-
-		if not os.path.exists(self.settings["storedir"]+"/builds/"):
-			os.makedirs(self.settings["storedir"]+"/builds/")
-
-	def copy_files_to_image(self):
-		# copies specific files from the buildroot to merge_path
-		myfiles=[]
-
-		# check for autoresume point
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"copy_files_to_image"):
-				print "Resume point detected, skipping target path setup operation..."
-		else:
-			if "netboot2/packages" in self.settings:
-				if type(self.settings["netboot2/packages"]) == types.StringType:
-					loopy=[self.settings["netboot2/packages"]]
-				else:
-					loopy=self.settings["netboot2/packages"]
-
-			for x in loopy:
-				if "netboot2/packages/"+x+"/files" in self.settings:
-				    if type(self.settings["netboot2/packages/"+x+"/files"]) == types.ListType:
-					    myfiles.extend(self.settings["netboot2/packages/"+x+"/files"])
-				    else:
-					    myfiles.append(self.settings["netboot2/packages/"+x+"/files"])
-
-			if "netboot2/extra_files" in self.settings:
-				if type(self.settings["netboot2/extra_files"]) == types.ListType:
-					myfiles.extend(self.settings["netboot2/extra_files"])
-				else:
-					myfiles.append(self.settings["netboot2/extra_files"])
-
-			try:
-				cmd("/bin/bash "+self.settings["controller_file"]+\
-					" image " + list_bashify(myfiles),env=self.env)
-			except CatalystError:
-				self.unbind()
-				raise CatalystError,"Failed to copy files to image!"
-
-			touch(self.settings["autoresume_path"]+"copy_files_to_image")
-
-	def setup_overlay(self):
-		if "AUTORESUME" in self.settings \
-		and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
-			print "Resume point detected, skipping setup_overlay operation..."
-		else:
-			if "netboot2/overlay" in self.settings:
-				for x in self.settings["netboot2/overlay"]:
-					if os.path.exists(x):
-						cmd("rsync -a "+x+"/ "+\
-							self.settings["chroot_path"] + self.settings["merge_path"], "netboot2/overlay: "+x+" copy failed.",env=self.env)
-				touch(self.settings["autoresume_path"]+"setup_overlay")
-
-	def move_kernels(self):
-		# we're done, move the kernels to builds/*
-		# no auto resume here as we always want the
-		# freshest images moved
-		try:
-			cmd("/bin/bash "+self.settings["controller_file"]+\
-				" final",env=self.env)
-			print ">>> Netboot Build Finished!"
-		except CatalystError:
-			self.unbind()
-			raise CatalystError,"Failed to move kernel images!"
-
-	def remove(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"remove"):
-			print "Resume point detected, skipping remove operation..."
-		else:
-			if self.settings["spec_prefix"]+"/rm" in self.settings:
-				for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
-					# we're going to shell out for all these cleaning operations,
-					# so we get easy glob handling
-					print "netboot2: removing " + x
-					os.system("rm -rf " + self.settings["chroot_path"] + self.settings["merge_path"] + x)
-
-	def empty(self):
-		if "AUTORESUME" in self.settings \
-			and os.path.exists(self.settings["autoresume_path"]+"empty"):
-			print "Resume point detected, skipping empty operation..."
-		else:
-			if "netboot2/empty" in self.settings:
-				if type(self.settings["netboot2/empty"])==types.StringType:
-					self.settings["netboot2/empty"]=self.settings["netboot2/empty"].split()
-				for x in self.settings["netboot2/empty"]:
-					myemp=self.settings["chroot_path"] + self.settings["merge_path"] + x
-					if not os.path.isdir(myemp):
-						print x,"not a directory or does not exist, skipping 'empty' operation."
-						continue
-					print "Emptying directory", x
-					# stat the dir, delete the dir, recreate the dir and set
-					# the proper perms and ownership
-					mystat=os.stat(myemp)
-					shutil.rmtree(myemp)
-					os.makedirs(myemp,0755)
-					os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
-					os.chmod(myemp,mystat[ST_MODE])
-		touch(self.settings["autoresume_path"]+"empty")
-
-	def set_action_sequence(self):
-	    self.settings["action_sequence"]=["unpack","unpack_snapshot","config_profile_link",
-	    				"setup_confdir","portage_overlay","bind","chroot_setup",\
-					"setup_environment","build_packages","root_overlay",\
-					"copy_files_to_image","setup_overlay","build_kernel","move_kernels",\
-					"remove","empty","unbind","clean","clear_autoresume"]
-
-def register(foo):
-	foo.update({"netboot2":netboot2_target})
-	return foo
diff --git a/catalyst/modules/netboot_target.py b/catalyst/modules/netboot_target.py
deleted file mode 100644
index 9d01b7e..0000000
--- a/catalyst/modules/netboot_target.py
+++ /dev/null
@@ -1,128 +0,0 @@
-"""
-netboot target, version 1
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-import os,string,types
-from catalyst.support import *
-from generic_stage_target import *
-
-class netboot_target(generic_stage_target):
-	"""
-	Builder class for a netboot build.
-	"""
-	def __init__(self,spec,addlargs):
-		self.valid_values = [
-			"netboot/kernel/sources",
-			"netboot/kernel/config",
-			"netboot/kernel/prebuilt",
-
-			"netboot/busybox_config",
-
-			"netboot/extra_files",
-			"netboot/packages"
-		]
-		self.required_values=[]
-
-		try:
-			if "netboot/packages" in addlargs:
-				if type(addlargs["netboot/packages"]) == types.StringType:
-					loopy=[addlargs["netboot/packages"]]
-				else:
-					loopy=addlargs["netboot/packages"]
-
-		#	for x in loopy:
-		#		self.required_values.append("netboot/packages/"+x+"/files")
-		except:
-			raise CatalystError,"configuration error in netboot/packages."
-
-		generic_stage_target.__init__(self,spec,addlargs)
-		self.set_build_kernel_vars(addlargs)
-		if "netboot/busybox_config" in addlargs:
-			file_locate(self.settings, ["netboot/busybox_config"])
-
-		# Custom Kernel Tarball --- use that instead ...
-
-		# unless the user wants specific CFLAGS/CXXFLAGS, let's use -Os
-
-		for envvar in "CFLAGS", "CXXFLAGS":
-			if envvar not in os.environ and envvar not in addlargs:
-				self.settings[envvar] = "-Os -pipe"
-
-	def set_root_path(self):
-		# ROOT= variable for emerges
-		self.settings["root_path"]=normpath("/tmp/image")
-		print "netboot root path is "+self.settings["root_path"]
-
-#	def build_packages(self):
-#		# build packages
-#		if "netboot/packages" in self.settings:
-#			mypack=list_bashify(self.settings["netboot/packages"])
-#		try:
-#			cmd("/bin/bash "+self.settings["controller_file"]+" packages "+mypack,env=self.env)
-#		except CatalystError:
-#			self.unbind()
-#			raise CatalystError,"netboot build aborting due to error."
-
-	def build_busybox(self):
-		# build busybox
-		if "netboot/busybox_config" in self.settings:
-			mycmd = self.settings["netboot/busybox_config"]
-		else:
-			mycmd = ""
-		try:
-			cmd("/bin/bash "+self.settings["controller_file"]+" busybox "+ mycmd,env=self.env)
-		except CatalystError:
-			self.unbind()
-			raise CatalystError,"netboot build aborting due to error."
-
-	def copy_files_to_image(self):
-		# create image
-		myfiles=[]
-		if "netboot/packages" in self.settings:
-			if type(self.settings["netboot/packages"]) == types.StringType:
-				loopy=[self.settings["netboot/packages"]]
-			else:
-				loopy=self.settings["netboot/packages"]
-
-		for x in loopy:
-			if "netboot/packages/"+x+"/files" in self.settings:
-			    if type(self.settings["netboot/packages/"+x+"/files"]) == types.ListType:
-				    myfiles.extend(self.settings["netboot/packages/"+x+"/files"])
-			    else:
-				    myfiles.append(self.settings["netboot/packages/"+x+"/files"])
-
-		if "netboot/extra_files" in self.settings:
-			if type(self.settings["netboot/extra_files"]) == types.ListType:
-				myfiles.extend(self.settings["netboot/extra_files"])
-			else:
-				myfiles.append(self.settings["netboot/extra_files"])
-
-		try:
-			cmd("/bin/bash "+self.settings["controller_file"]+\
-				" image " + list_bashify(myfiles),env=self.env)
-		except CatalystError:
-			self.unbind()
-			raise CatalystError,"netboot build aborting due to error."
-
-	def create_netboot_files(self):
-		# finish it all up
-		try:
-			cmd("/bin/bash "+self.settings["controller_file"]+" finish",env=self.env)
-		except CatalystError:
-			self.unbind()
-			raise CatalystError,"netboot build aborting due to error."
-
-		# end
-		print "netboot: build finished !"
-
-	def set_action_sequence(self):
-	    self.settings["action_sequence"]=["unpack","unpack_snapshot",
-	    				"config_profile_link","setup_confdir","bind","chroot_setup",\
-						"setup_environment","build_packages","build_busybox",\
-						"build_kernel","copy_files_to_image",\
-						"clean","create_netboot_files","unbind","clear_autoresume"]
-
-def register(foo):
-	foo.update({"netboot":netboot_target})
-	return foo
diff --git a/catalyst/modules/snapshot_target.py b/catalyst/modules/snapshot_target.py
deleted file mode 100644
index e21bd1a..0000000
--- a/catalyst/modules/snapshot_target.py
+++ /dev/null
@@ -1,91 +0,0 @@
-"""
-Snapshot target
-"""
-
-import os
-from catalyst.support import *
-from generic_stage_target import *
-
-class snapshot_target(generic_stage_target):
-	"""
-	Builder class for snapshots.
-	"""
-	def __init__(self,myspec,addlargs):
-		self.required_values=["version_stamp","target"]
-		self.valid_values=["version_stamp","target"]
-
-		generic_target.__init__(self,myspec,addlargs)
-		self.settings=myspec
-		self.settings["target_subpath"]="portage"
-		st=self.settings["storedir"]
-		self.settings["snapshot_path"]=normpath(st + "/snapshots/"
-			+ self.settings["snapshot_name"]
-			+ self.settings["version_stamp"] + ".tar.bz2")
-		self.settings["tmp_path"]=normpath(st+"/tmp/"+self.settings["target_subpath"])
-
-	def setup(self):
-		x=normpath(self.settings["storedir"]+"/snapshots")
-		if not os.path.exists(x):
-			os.makedirs(x)
-
-	def mount_safety_check(self):
-		pass
-
-	def run(self):
-		if "PURGEONLY" in self.settings:
-			self.purge()
-			return
-
-		if "PURGE" in self.settings:
-			self.purge()
-
-		self.setup()
-		print "Creating Portage tree snapshot "+self.settings["version_stamp"]+\
-			" from "+self.settings["portdir"]+"..."
-
-		mytmp=self.settings["tmp_path"]
-		if not os.path.exists(mytmp):
-			os.makedirs(mytmp)
-
-		cmd("rsync -a --delete --exclude /packages/ --exclude /distfiles/ " +
-			"--exclude /local/ --exclude CVS/ --exclude .svn --filter=H_**/files/digest-* " +
-			self.settings["portdir"] + "/ " + mytmp + "/%s/" % self.settings["repo_name"],
-			"Snapshot failure",env=self.env)
-
-		print "Compressing Portage snapshot tarball..."
-		cmd("tar -I lbzip2 -cf " + self.settings["snapshot_path"] + " -C " +
-			mytmp + " %s" % self.settings["repo_name"],
-			"Snapshot creation failure",env=self.env)
-
-		self.gen_contents_file(self.settings["snapshot_path"])
-		self.gen_digest_file(self.settings["snapshot_path"])
-
-		self.cleanup()
-		print "snapshot: complete!"
-
-	def kill_chroot_pids(self):
-		pass
-
-	def cleanup(self):
-		print "Cleaning up..."
-
-	def purge(self):
-		myemp=self.settings["tmp_path"]
-		if os.path.isdir(myemp):
-			print "Emptying directory",myemp
-			"""
-			stat the dir, delete the dir, recreate the dir and set
-			the proper perms and ownership
-			"""
-			mystat=os.stat(myemp)
-			""" There's no easy way to change flags recursively in python """
-			if os.uname()[0] == "FreeBSD":
-				os.system("chflags -R noschg "+myemp)
-			shutil.rmtree(myemp)
-			os.makedirs(myemp,0755)
-			os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
-			os.chmod(myemp,mystat[ST_MODE])
-
-def register(foo):
-	foo.update({"snapshot":snapshot_target})
-	return foo
diff --git a/catalyst/modules/stage1_target.py b/catalyst/modules/stage1_target.py
deleted file mode 100644
index 25f7116..0000000
--- a/catalyst/modules/stage1_target.py
+++ /dev/null
@@ -1,96 +0,0 @@
-"""
-stage1 target
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-from catalyst.support import *
-from generic_stage_target import *
-
-class stage1_target(generic_stage_target):
-	"""
-	Builder class for a stage1 installation tarball build.
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=[]
-		self.valid_values=["chost"]
-		self.valid_values.extend(["update_seed","update_seed_command"])
-		generic_stage_target.__init__(self,spec,addlargs)
-
-	def set_stage_path(self):
-		self.settings["stage_path"]=normpath(self.settings["chroot_path"]+self.settings["root_path"])
-		print "stage1 stage path is "+self.settings["stage_path"]
-
-	def set_root_path(self):
-		# sets the root path, relative to 'chroot_path', of the stage1 root
-		self.settings["root_path"]=normpath("/tmp/stage1root")
-		print "stage1 root path is "+self.settings["root_path"]
-
-	def set_cleanables(self):
-		generic_stage_target.set_cleanables(self)
-		self.settings["cleanables"].extend([\
-		"/usr/share/zoneinfo", "/etc/portage/package*"])
-
-	# XXX: How do these override_foo() functions differ from the ones in generic_stage_target and why aren't they in stage3_target?
-
-	def override_chost(self):
-		if "chost" in self.settings:
-			self.settings["CHOST"]=list_to_string(self.settings["chost"])
-
-	def override_cflags(self):
-		if "cflags" in self.settings:
-			self.settings["CFLAGS"]=list_to_string(self.settings["cflags"])
-
-	def override_cxxflags(self):
-		if "cxxflags" in self.settings:
-			self.settings["CXXFLAGS"]=list_to_string(self.settings["cxxflags"])
-
-	def override_ldflags(self):
-		if "ldflags" in self.settings:
-			self.settings["LDFLAGS"]=list_to_string(self.settings["ldflags"])
-
-	def set_portage_overlay(self):
-		generic_stage_target.set_portage_overlay(self)
-		if "portage_overlay" in self.settings:
-			print "\nWARNING !!!!!"
-			print "\tUsing an portage overlay for earlier stages could cause build issues."
-			print "\tIf you break it, you buy it. Don't complain to us about it."
-			print "\tDont say we did not warn you\n"
-
-	def base_dirs(self):
-		if os.uname()[0] == "FreeBSD":
-			# baselayout no longer creates the .keep files in proc and dev for FreeBSD as it
-			# would create them too late...we need them earlier before bind mounting filesystems
-			# since proc and dev are not writeable, so...create them here
-			if not os.path.exists(self.settings["stage_path"]+"/proc"):
-				os.makedirs(self.settings["stage_path"]+"/proc")
-			if not os.path.exists(self.settings["stage_path"]+"/dev"):
-				os.makedirs(self.settings["stage_path"]+"/dev")
-			if not os.path.isfile(self.settings["stage_path"]+"/proc/.keep"):
-				try:
-					proc_keepfile = open(self.settings["stage_path"]+"/proc/.keep","w")
-					proc_keepfile.write('')
-					proc_keepfile.close()
-				except IOError:
-					print "!!! Failed to create %s" % (self.settings["stage_path"]+"/dev/.keep")
-			if not os.path.isfile(self.settings["stage_path"]+"/dev/.keep"):
-				try:
-					dev_keepfile = open(self.settings["stage_path"]+"/dev/.keep","w")
-					dev_keepfile.write('')
-					dev_keepfile.close()
-				except IOError:
-					print "!!! Failed to create %s" % (self.settings["stage_path"]+"/dev/.keep")
-		else:
-			pass
-
-	def set_mounts(self):
-		# stage_path/proc probably doesn't exist yet, so create it
-		if not os.path.exists(self.settings["stage_path"]+"/proc"):
-			os.makedirs(self.settings["stage_path"]+"/proc")
-
-		# alter the mount mappings to bind mount proc onto it
-		self.mounts.append("/tmp/stage1root/proc")
-		self.mountmap["/tmp/stage1root/proc"]="/proc"
-
-def register(foo):
-	foo.update({"stage1":stage1_target})
-	return foo
diff --git a/catalyst/modules/stage2_target.py b/catalyst/modules/stage2_target.py
deleted file mode 100644
index 15acdee..0000000
--- a/catalyst/modules/stage2_target.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""
-stage2 target, builds upon previous stage1 tarball
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-from catalyst.support import *
-from generic_stage_target import *
-
-class stage2_target(generic_stage_target):
-	"""
-	Builder class for a stage2 installation tarball build.
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=[]
-		self.valid_values=["chost"]
-		generic_stage_target.__init__(self,spec,addlargs)
-
-	def set_source_path(self):
-		if "SEEDCACHE" in self.settings and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/tmp/stage1root/")):
-			self.settings["source_path"]=normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/tmp/stage1root/")
-		else:
-			self.settings["source_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2")
-			if os.path.isfile(self.settings["source_path"]):
-				if os.path.exists(self.settings["source_path"]):
-				# XXX: Is this even necessary if the previous check passes?
-					self.settings["source_path_hash"]=generate_hash(self.settings["source_path"],\
-						hash_function=self.settings["hash_function"],verbose=False)
-		print "Source path set to "+self.settings["source_path"]
-		if os.path.isdir(self.settings["source_path"]):
-			print "\tIf this is not desired, remove this directory or turn of seedcache in the options of catalyst.conf"
-			print "\tthe source path will then be "+normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2\n")
-
-	# XXX: How do these override_foo() functions differ from the ones in
-	# generic_stage_target and why aren't they in stage3_target?
-
-	def override_chost(self):
-		if "chost" in self.settings:
-			self.settings["CHOST"]=list_to_string(self.settings["chost"])
-
-	def override_cflags(self):
-		if "cflags" in self.settings:
-			self.settings["CFLAGS"]=list_to_string(self.settings["cflags"])
-
-	def override_cxxflags(self):
-		if "cxxflags" in self.settings:
-			self.settings["CXXFLAGS"]=list_to_string(self.settings["cxxflags"])
-
-	def override_ldflags(self):
-		if "ldflags" in self.settings:
-			self.settings["LDFLAGS"]=list_to_string(self.settings["ldflags"])
-
-	def set_portage_overlay(self):
-			generic_stage_target.set_portage_overlay(self)
-			if "portage_overlay" in self.settings:
-				print "\nWARNING !!!!!"
-				print "\tUsing an portage overlay for earlier stages could cause build issues."
-				print "\tIf you break it, you buy it. Don't complain to us about it."
-				print "\tDont say we did not warn you\n"
-
-def register(foo):
-	foo.update({"stage2":stage2_target})
-	return foo
diff --git a/catalyst/modules/stage3_target.py b/catalyst/modules/stage3_target.py
deleted file mode 100644
index 89edd66..0000000
--- a/catalyst/modules/stage3_target.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""
-stage3 target, builds upon previous stage2/stage3 tarball
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-from catalyst.support import *
-from generic_stage_target import *
-
-class stage3_target(generic_stage_target):
-	"""
-	Builder class for a stage3 installation tarball build.
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=[]
-		self.valid_values=[]
-		generic_stage_target.__init__(self,spec,addlargs)
-
-	def set_portage_overlay(self):
-		generic_stage_target.set_portage_overlay(self)
-		if "portage_overlay" in self.settings:
-			print "\nWARNING !!!!!"
-			print "\tUsing an overlay for earlier stages could cause build issues."
-			print "\tIf you break it, you buy it. Don't complain to us about it."
-			print "\tDont say we did not warn you\n"
-
-	def set_cleanables(self):
-		generic_stage_target.set_cleanables(self)
-
-def register(foo):
-	foo.update({"stage3":stage3_target})
-	return foo
diff --git a/catalyst/modules/stage4_target.py b/catalyst/modules/stage4_target.py
deleted file mode 100644
index 9168f2e..0000000
--- a/catalyst/modules/stage4_target.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-stage4 target, builds upon previous stage3/stage4 tarball
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-from catalyst.support import *
-from generic_stage_target import *
-
-class stage4_target(generic_stage_target):
-	"""
-	Builder class for stage4.
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=["stage4/packages"]
-		self.valid_values=self.required_values[:]
-		self.valid_values.extend(["stage4/use","boot/kernel",\
-				"stage4/root_overlay","stage4/fsscript",\
-				"stage4/gk_mainargs","splash_theme",\
-				"portage_overlay","stage4/rcadd","stage4/rcdel",\
-				"stage4/linuxrc","stage4/unmerge","stage4/rm","stage4/empty"])
-		generic_stage_target.__init__(self,spec,addlargs)
-
-	def set_cleanables(self):
-		self.settings["cleanables"]=["/var/tmp/*","/tmp/*"]
-
-	def set_action_sequence(self):
-		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
-					"config_profile_link","setup_confdir","portage_overlay",\
-					"bind","chroot_setup","setup_environment","build_packages",\
-					"build_kernel","bootloader","root_overlay","fsscript",\
-					"preclean","rcupdate","unmerge","unbind","remove","empty",\
-					"clean"]
-
-#		if "TARBALL" in self.settings or \
-#			"FETCH" not in self.settings:
-		if "FETCH" not in self.settings:
-			self.settings["action_sequence"].append("capture")
-		self.settings["action_sequence"].append("clear_autoresume")
-
-def register(foo):
-	foo.update({"stage4":stage4_target})
-	return foo
-
diff --git a/catalyst/modules/tinderbox_target.py b/catalyst/modules/tinderbox_target.py
deleted file mode 100644
index 5985c5b..0000000
--- a/catalyst/modules/tinderbox_target.py
+++ /dev/null
@@ -1,44 +0,0 @@
-"""
-Tinderbox target
-"""
-# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
-
-from catalyst.support import *
-from generic_stage_target import *
-
-class tinderbox_target(generic_stage_target):
-	"""
-	Builder class for the tinderbox target
-	"""
-	def __init__(self,spec,addlargs):
-		self.required_values=["tinderbox/packages"]
-		self.valid_values=self.required_values[:]
-		self.valid_values.extend(["tinderbox/use"])
-		generic_stage_target.__init__(self,spec,addlargs)
-
-	def run_local(self):
-		# tinderbox
-		# example call: "grp.sh run xmms vim sys-apps/gleep"
-		try:
-			if os.path.exists(self.settings["controller_file"]):
-			    cmd("/bin/bash "+self.settings["controller_file"]+" run "+\
-				list_bashify(self.settings["tinderbox/packages"]),"run script failed.",env=self.env)
-
-		except CatalystError:
-			self.unbind()
-			raise CatalystError,"Tinderbox aborting due to error."
-
-	def set_cleanables(self):
-	    self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/root/*",
-					self.settings['portdir']]
-
-	def set_action_sequence(self):
-		#Default action sequence for run method
-		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
-		              "config_profile_link","setup_confdir","bind","chroot_setup",\
-		              "setup_environment","run_local","preclean","unbind","clean",\
-		              "clear_autoresume"]
-
-def register(foo):
-	foo.update({"tinderbox":tinderbox_target})
-	return foo
diff --git a/catalyst/targets/__init__.py b/catalyst/targets/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/catalyst/targets/__init__.py
@@ -0,0 +1 @@
+
diff --git a/catalyst/targets/embedded_target.py b/catalyst/targets/embedded_target.py
new file mode 100644
index 0000000..7cee7a6
--- /dev/null
+++ b/catalyst/targets/embedded_target.py
@@ -0,0 +1,51 @@
+"""
+Enbedded target, similar to the stage2 target, builds upon a stage2 tarball.
+
+A stage2 tarball is unpacked, but instead
+of building a stage3, it emerges @system into another directory
+inside the stage2 system.  This way, we do not have to emerge GCC/portage
+into the staged system.
+It may sound complicated but basically it runs
+ROOT=/tmp/submerge emerge --something foo bar .
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+import os,string,imp,types,shutil
+from catalyst.support import *
+from generic_stage_target import *
+from stat import *
+
+class embedded_target(generic_stage_target):
+	"""
+	Builder class for embedded target
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=[]
+		self.valid_values=[]
+		self.valid_values.extend(["embedded/empty","embedded/rm","embedded/unmerge","embedded/fs-prepare","embedded/fs-finish","embedded/mergeroot","embedded/packages","embedded/fs-type","embedded/runscript","boot/kernel","embedded/linuxrc"])
+		self.valid_values.extend(["embedded/use"])
+		if "embedded/fs-type" in addlargs:
+			self.valid_values.append("embedded/fs-ops")
+
+		generic_stage_target.__init__(self,spec,addlargs)
+		self.set_build_kernel_vars(addlargs)
+
+	def set_action_sequence(self):
+		self.settings["action_sequence"]=["dir_setup","unpack","unpack_snapshot",\
+					"config_profile_link","setup_confdir",\
+					"portage_overlay","bind","chroot_setup",\
+					"setup_environment","build_kernel","build_packages",\
+					"bootloader","root_overlay","fsscript","unmerge",\
+					"unbind","remove","empty","clean","capture","clear_autoresume"]
+
+	def set_stage_path(self):
+		self.settings["stage_path"]=normpath(self.settings["chroot_path"]+"/tmp/mergeroot")
+		print "embedded stage path is "+self.settings["stage_path"]
+
+	def set_root_path(self):
+		self.settings["root_path"]=normpath("/tmp/mergeroot")
+		print "embedded root path is "+self.settings["root_path"]
+
+def register(foo):
+	foo.update({"embedded":embedded_target})
+	return foo
diff --git a/catalyst/targets/generic_stage_target.py b/catalyst/targets/generic_stage_target.py
new file mode 100644
index 0000000..5200d8a
--- /dev/null
+++ b/catalyst/targets/generic_stage_target.py
@@ -0,0 +1,1691 @@
+import os,string,imp,types,shutil
+from catalyst.support import *
+from generic_target import *
+from stat import *
+from catalyst.lock import LockDir
+
+class generic_stage_target(generic_target):
+	"""
+	This class does all of the chroot setup, copying of files, etc. It is
+	the driver class for pretty much everything that Catalyst does.
+	"""
+	def __init__(self,myspec,addlargs):
+		self.required_values.extend(["version_stamp","target","subarch",\
+			"rel_type","profile","snapshot","source_subpath"])
+
+		self.valid_values.extend(["version_stamp","target","subarch",\
+			"rel_type","profile","snapshot","source_subpath","portage_confdir",\
+			"cflags","cxxflags","ldflags","cbuild","hostuse","portage_overlay",\
+			"distcc_hosts","makeopts","pkgcache_path","kerncache_path"])
+
+		self.set_valid_build_kernel_vars(addlargs)
+		generic_target.__init__(self,myspec,addlargs)
+
+		"""
+		The semantics of subarchmap and machinemap changed a bit in 2.0.3 to
+		work better with vapier's CBUILD stuff. I've removed the "monolithic"
+		machinemap from this file and split up its contents amongst the
+		various arch/foo.py files.
+
+		When register() is called on each module in the arch/ dir, it now
+		returns a tuple instead of acting on the subarchmap dict that is
+		passed to it. The tuple contains the values that were previously
+		added to subarchmap as well as a new list of CHOSTs that go along
+		with that arch. This allows us to build machinemap on the fly based
+		on the keys in subarchmap and the values of the 2nd list returned
+		(tmpmachinemap).
+
+		Also, after talking with vapier. I have a slightly better idea of what
+		certain variables are used for and what they should be set to. Neither
+		'buildarch' or 'hostarch' are used directly, so their value doesn't
+		really matter. They are just compared to determine if we are
+		cross-compiling. Because of this, they are just set to the name of the
+		module in arch/ that the subarch is part of to make things simpler.
+		The entire build process is still based off of 'subarch' like it was
+		previously. -agaffney
+		"""
+
+		self.archmap = {}
+		self.subarchmap = {}
+		machinemap = {}
+		arch_dir = self.settings["PythonDir"] + "/arch/"
+		for x in [x[:-3] for x in os.listdir(arch_dir) if x.endswith(".py")]:
+			try:
+				fh=open(arch_dir + x + ".py")
+				"""
+				This next line loads the plugin as a module and assigns it to
+				archmap[x]
+				"""
+				self.archmap[x]=imp.load_module(x,fh,"../arch/" + x + ".py",
+					(".py", "r", imp.PY_SOURCE))
+				"""
+				This next line registers all the subarches supported in the
+				plugin
+				"""
+				tmpsubarchmap, tmpmachinemap = self.archmap[x].register()
+				self.subarchmap.update(tmpsubarchmap)
+				for machine in tmpmachinemap:
+					machinemap[machine] = x
+				for subarch in tmpsubarchmap:
+					machinemap[subarch] = x
+				fh.close()
+			except IOError:
+				"""
+				This message should probably change a bit, since everything in
+				the dir should load just fine. If it doesn't, it's probably a
+				syntax error in the module
+				"""
+				msg("Can't find/load " + x + ".py plugin in " + arch_dir)
+
+		if "chost" in self.settings:
+			hostmachine = self.settings["chost"].split("-")[0]
+			if hostmachine not in machinemap:
+				raise CatalystError, "Unknown host machine type "+hostmachine
+			self.settings["hostarch"]=machinemap[hostmachine]
+		else:
+			hostmachine = self.settings["subarch"]
+			if hostmachine in machinemap:
+				hostmachine = machinemap[hostmachine]
+			self.settings["hostarch"]=hostmachine
+		if "cbuild" in self.settings:
+			buildmachine = self.settings["cbuild"].split("-")[0]
+		else:
+			buildmachine = os.uname()[4]
+		if buildmachine not in machinemap:
+			raise CatalystError, "Unknown build machine type "+buildmachine
+		self.settings["buildarch"]=machinemap[buildmachine]
+		self.settings["crosscompile"]=(self.settings["hostarch"]!=\
+			self.settings["buildarch"])
+
+		""" Call arch constructor, pass our settings """
+		try:
+			self.arch=self.subarchmap[self.settings["subarch"]](self.settings)
+		except KeyError:
+			print "Invalid subarch: "+self.settings["subarch"]
+			print "Choose one of the following:",
+			for x in self.subarchmap:
+				print x,
+			print
+			sys.exit(2)
+
+		print "Using target:",self.settings["target"]
+		""" Print a nice informational message """
+		if self.settings["buildarch"]==self.settings["hostarch"]:
+			print "Building natively for",self.settings["hostarch"]
+		elif self.settings["crosscompile"]:
+			print "Cross-compiling on",self.settings["buildarch"],\
+				"for different machine type",self.settings["hostarch"]
+		else:
+			print "Building on",self.settings["buildarch"],\
+				"for alternate personality type",self.settings["hostarch"]
+
+		""" This must be set first as other set_ options depend on this """
+		self.set_spec_prefix()
+
+		""" Define all of our core variables """
+		self.set_target_profile()
+		self.set_target_subpath()
+		self.set_source_subpath()
+
+		""" Set paths """
+		self.set_snapshot_path()
+		self.set_root_path()
+		self.set_source_path()
+		self.set_snapcache_path()
+		self.set_chroot_path()
+		self.set_autoresume_path()
+		self.set_dest_path()
+		self.set_stage_path()
+		self.set_target_path()
+
+		self.set_controller_file()
+		self.set_action_sequence()
+		self.set_use()
+		self.set_cleanables()
+		self.set_iso_volume_id()
+		self.set_build_kernel_vars()
+		self.set_fsscript()
+		self.set_install_mask()
+		self.set_rcadd()
+		self.set_rcdel()
+		self.set_cdtar()
+		self.set_fstype()
+		self.set_fsops()
+		self.set_iso()
+		self.set_packages()
+		self.set_rm()
+		self.set_linuxrc()
+		self.set_busybox_config()
+		self.set_overlay()
+		self.set_portage_overlay()
+		self.set_root_overlay()
+
+		"""
+		This next line checks to make sure that the specified variables exist
+		on disk.
+		"""
+		#pdb.set_trace()
+		file_locate(self.settings,["source_path","snapshot_path","distdir"],\
+			expand=0)
+		""" If we are using portage_confdir, check that as well. """
+		if "portage_confdir" in self.settings:
+			file_locate(self.settings,["portage_confdir"],expand=0)
+
+		""" Setup our mount points """
+		if "SNAPCACHE" in self.settings:
+			self.mounts=["/proc","/dev","/usr/portage","/usr/portage/distfiles","/var/tmp/portage"]
+			self.mountmap={"/proc":"/proc","/dev":"/dev","/dev/pts":"/dev/pts",\
+				"/usr/portage":self.settings["snapshot_cache_path"]+"/portage",\
+				"/usr/portage/distfiles":self.settings["distdir"],"/var/tmp/portage":"tmpfs"}
+		else:
+			self.mounts=["proc","dev", "distdir", "port_tmpdir"]
+			self.mountmap={"proc":"/proc", "dev":"/dev", "pts":"/dev/pts",
+				"distdir":self.settings["distdir"], "port_tmpdir":"tmpfs"}
+		if os.uname()[0] == "Linux":
+			self.mounts.append("pts")
+
+		self.set_mounts()
+
+		"""
+		Configure any user specified options (either in catalyst.conf or on
+		the command line).
+		"""
+		if "PKGCACHE" in self.settings:
+			self.set_pkgcache_path()
+			print "Location of the package cache is "+\
+				self.settings["pkgcache_path"]
+			self.mounts.append("packagedir")
+			self.mountmap["packagedir"] = self.settings["pkgcache_path"]
+
+		if "KERNCACHE" in self.settings:
+			self.set_kerncache_path()
+			print "Location of the kerncache is "+\
+				self.settings["kerncache_path"]
+			self.mounts.append("kerncache")
+			self.mountmap["kerncache"]=self.settings["kerncache_path"]
+
+		if "CCACHE" in self.settings:
+			if "CCACHE_DIR" in os.environ:
+				ccdir=os.environ["CCACHE_DIR"]
+				del os.environ["CCACHE_DIR"]
+			else:
+				ccdir="/root/.ccache"
+			if not os.path.isdir(ccdir):
+				raise CatalystError,\
+					"Compiler cache support can't be enabled (can't find "+\
+					ccdir+")"
+			self.mounts.append("ccache")
+			self.mountmap["ccache"]=ccdir
+			""" for the chroot: """
+			self.env["CCACHE_DIR"]="/var/tmp/ccache"
+
+		if "ICECREAM" in self.settings:
+			self.mounts.append("/var/cache/icecream")
+			self.mountmap["/var/cache/icecream"]="/var/cache/icecream"
+			self.env["PATH"]="/usr/lib/icecc/bin:"+self.env["PATH"]
+
+		if "port_logdir" in self.settings:
+			self.mounts.append("/var/log/portage")
+			self.mountmap["/var/log/portage"]=self.settings["port_logdir"]
+			self.env["PORT_LOGDIR"]="/var/log/portage"
+			self.env["PORT_LOGDIR_CLEAN"]='find "${PORT_LOGDIR}" -type f ! -name "summary.log*" -mtime +30 -delete'
+
+	def override_cbuild(self):
+		if "CBUILD" in self.makeconf:
+			self.settings["CBUILD"]=self.makeconf["CBUILD"]
+
+	def override_chost(self):
+		if "CHOST" in self.makeconf:
+			self.settings["CHOST"]=self.makeconf["CHOST"]
+
+	def override_cflags(self):
+		if "CFLAGS" in self.makeconf:
+			self.settings["CFLAGS"]=self.makeconf["CFLAGS"]
+
+	def override_cxxflags(self):
+		if "CXXFLAGS" in self.makeconf:
+			self.settings["CXXFLAGS"]=self.makeconf["CXXFLAGS"]
+
+	def override_ldflags(self):
+		if "LDFLAGS" in self.makeconf:
+			self.settings["LDFLAGS"]=self.makeconf["LDFLAGS"]
+
+	def set_install_mask(self):
+		if "install_mask" in self.settings:
+			if type(self.settings["install_mask"])!=types.StringType:
+				self.settings["install_mask"]=\
+					string.join(self.settings["install_mask"])
+
+	def set_spec_prefix(self):
+		self.settings["spec_prefix"]=self.settings["target"]
+
+	def set_target_profile(self):
+		self.settings["target_profile"]=self.settings["profile"]
+
+	def set_target_subpath(self):
+		self.settings["target_subpath"]=self.settings["rel_type"]+"/"+\
+				self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
+				self.settings["version_stamp"]
+
+	def set_source_subpath(self):
+		if type(self.settings["source_subpath"])!=types.StringType:
+			raise CatalystError,\
+				"source_subpath should have been a string. Perhaps you have something wrong in your spec file?"
+
+	def set_pkgcache_path(self):
+		if "pkgcache_path" in self.settings:
+			if type(self.settings["pkgcache_path"])!=types.StringType:
+				self.settings["pkgcache_path"]=\
+					normpath(string.join(self.settings["pkgcache_path"]))
+		else:
+			self.settings["pkgcache_path"]=\
+				normpath(self.settings["storedir"]+"/packages/"+\
+				self.settings["target_subpath"]+"/")
+
+	def set_kerncache_path(self):
+		if "kerncache_path" in self.settings:
+			if type(self.settings["kerncache_path"])!=types.StringType:
+				self.settings["kerncache_path"]=\
+					normpath(string.join(self.settings["kerncache_path"]))
+		else:
+			self.settings["kerncache_path"]=normpath(self.settings["storedir"]+\
+				"/kerncache/"+self.settings["target_subpath"]+"/")
+
+	def set_target_path(self):
+		self.settings["target_path"]=normpath(self.settings["storedir"]+\
+			"/builds/"+self.settings["target_subpath"]+".tar.bz2")
+		if "AUTORESUME" in self.settings\
+			and os.path.exists(self.settings["autoresume_path"]+\
+				"setup_target_path"):
+			print \
+				"Resume point detected, skipping target path setup operation..."
+		else:
+			""" First clean up any existing target stuff """
+			# XXX WTF are we removing the old tarball before we start building the
+			# XXX new one? If the build fails, you don't want to be left with
+			# XXX nothing at all
+#			if os.path.isfile(self.settings["target_path"]):
+#				cmd("rm -f "+self.settings["target_path"],\
+#					"Could not remove existing file: "\
+#					+self.settings["target_path"],env=self.env)
+			touch(self.settings["autoresume_path"]+"setup_target_path")
+
+			if not os.path.exists(self.settings["storedir"]+"/builds/"):
+				os.makedirs(self.settings["storedir"]+"/builds/")
+
+	def set_fsscript(self):
+		if self.settings["spec_prefix"]+"/fsscript" in self.settings:
+			self.settings["fsscript"]=\
+				self.settings[self.settings["spec_prefix"]+"/fsscript"]
+			del self.settings[self.settings["spec_prefix"]+"/fsscript"]
+
+	def set_rcadd(self):
+		if self.settings["spec_prefix"]+"/rcadd" in self.settings:
+			self.settings["rcadd"]=\
+				self.settings[self.settings["spec_prefix"]+"/rcadd"]
+			del self.settings[self.settings["spec_prefix"]+"/rcadd"]
+
+	def set_rcdel(self):
+		if self.settings["spec_prefix"]+"/rcdel" in self.settings:
+			self.settings["rcdel"]=\
+				self.settings[self.settings["spec_prefix"]+"/rcdel"]
+			del self.settings[self.settings["spec_prefix"]+"/rcdel"]
+
+	def set_cdtar(self):
+		if self.settings["spec_prefix"]+"/cdtar" in self.settings:
+			self.settings["cdtar"]=\
+				normpath(self.settings[self.settings["spec_prefix"]+"/cdtar"])
+			del self.settings[self.settings["spec_prefix"]+"/cdtar"]
+
+	def set_iso(self):
+		if self.settings["spec_prefix"]+"/iso" in self.settings:
+			if self.settings[self.settings["spec_prefix"]+"/iso"].startswith('/'):
+				self.settings["iso"]=\
+					normpath(self.settings[self.settings["spec_prefix"]+"/iso"])
+			else:
+				# This automatically prepends the build dir to the ISO output path
+				# if it doesn't start with a /
+				self.settings["iso"] = normpath(self.settings["storedir"] + \
+					"/builds/" + self.settings["rel_type"] + "/" + \
+					self.settings[self.settings["spec_prefix"]+"/iso"])
+			del self.settings[self.settings["spec_prefix"]+"/iso"]
+
+	def set_fstype(self):
+		if self.settings["spec_prefix"]+"/fstype" in self.settings:
+			self.settings["fstype"]=\
+				self.settings[self.settings["spec_prefix"]+"/fstype"]
+			del self.settings[self.settings["spec_prefix"]+"/fstype"]
+
+		if "fstype" not in self.settings:
+			self.settings["fstype"]="normal"
+			for x in self.valid_values:
+				if x ==  self.settings["spec_prefix"]+"/fstype":
+					print "\n"+self.settings["spec_prefix"]+\
+						"/fstype is being set to the default of \"normal\"\n"
+
+	def set_fsops(self):
+		if "fstype" in self.settings:
+			self.valid_values.append("fsops")
+			if self.settings["spec_prefix"]+"/fsops" in self.settings:
+				self.settings["fsops"]=\
+					self.settings[self.settings["spec_prefix"]+"/fsops"]
+				del self.settings[self.settings["spec_prefix"]+"/fsops"]
+
+	def set_source_path(self):
+		if "SEEDCACHE" in self.settings\
+			and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+\
+				self.settings["source_subpath"]+"/")):
+			self.settings["source_path"]=normpath(self.settings["storedir"]+\
+				"/tmp/"+self.settings["source_subpath"]+"/")
+		else:
+			self.settings["source_path"]=normpath(self.settings["storedir"]+\
+				"/builds/"+self.settings["source_subpath"]+".tar.bz2")
+			if os.path.isfile(self.settings["source_path"]):
+				# XXX: Is this even necessary if the previous check passes?
+				if os.path.exists(self.settings["source_path"]):
+					self.settings["source_path_hash"]=\
+						generate_hash(self.settings["source_path"],\
+						hash_function=self.settings["hash_function"],\
+						verbose=False)
+		print "Source path set to "+self.settings["source_path"]
+		if os.path.isdir(self.settings["source_path"]):
+			print "\tIf this is not desired, remove this directory or turn off"
+			print "\tseedcache in the options of catalyst.conf the source path"
+			print "\twill then be "+\
+				normpath(self.settings["storedir"]+"/builds/"+\
+				self.settings["source_subpath"]+".tar.bz2\n")
+
+	def set_dest_path(self):
+		if "root_path" in self.settings:
+			self.settings["destpath"]=normpath(self.settings["chroot_path"]+\
+				self.settings["root_path"])
+		else:
+			self.settings["destpath"]=normpath(self.settings["chroot_path"])
+
+	def set_cleanables(self):
+		self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/tmp/*",\
+			"/root/*", self.settings["portdir"]]
+
+	def set_snapshot_path(self):
+		self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
+			"/snapshots/" + self.settings["snapshot_name"] +
+			self.settings["snapshot"]+".tar.xz")
+
+		if os.path.exists(self.settings["snapshot_path"]):
+			self.settings["snapshot_path_hash"]=\
+				generate_hash(self.settings["snapshot_path"],\
+				hash_function=self.settings["hash_function"],verbose=False)
+		else:
+			self.settings["snapshot_path"]=normpath(self.settings["storedir"]+\
+				"/snapshots/" + self.settings["snapshot_name"] +
+				self.settings["snapshot"]+".tar.bz2")
+
+			if os.path.exists(self.settings["snapshot_path"]):
+				self.settings["snapshot_path_hash"]=\
+					generate_hash(self.settings["snapshot_path"],\
+					hash_function=self.settings["hash_function"],verbose=False)
+
+	def set_snapcache_path(self):
+		if "SNAPCACHE" in self.settings:
+			self.settings["snapshot_cache_path"]=\
+				normpath(self.settings["snapshot_cache"]+"/"+\
+				self.settings["snapshot"]+"/")
+			self.snapcache_lock=\
+				LockDir(self.settings["snapshot_cache_path"])
+			print "Caching snapshot to "+self.settings["snapshot_cache_path"]
+
+	def set_chroot_path(self):
+		"""
+		NOTE: the trailing slash is very important!
+		Things *will* break without it!
+		"""
+		self.settings["chroot_path"]=normpath(self.settings["storedir"]+\
+			"/tmp/"+self.settings["target_subpath"]+"/")
+		self.chroot_lock=LockDir(self.settings["chroot_path"])
+
+	def set_autoresume_path(self):
+		self.settings["autoresume_path"]=normpath(self.settings["storedir"]+\
+			"/tmp/"+self.settings["rel_type"]+"/"+".autoresume-"+\
+			self.settings["target"]+"-"+self.settings["subarch"]+"-"+\
+			self.settings["version_stamp"]+"/")
+		if "AUTORESUME" in self.settings:
+			print "The autoresume path is " + self.settings["autoresume_path"]
+		if not os.path.exists(self.settings["autoresume_path"]):
+			os.makedirs(self.settings["autoresume_path"],0755)
+
+	def set_controller_file(self):
+		self.settings["controller_file"]=normpath(self.settings["sharedir"]+\
+			"/targets/"+self.settings["target"]+"/"+self.settings["target"]+\
+			"-controller.sh")
+
+	def set_iso_volume_id(self):
+		if self.settings["spec_prefix"]+"/volid" in self.settings:
+			self.settings["iso_volume_id"]=\
+				self.settings[self.settings["spec_prefix"]+"/volid"]
+			if len(self.settings["iso_volume_id"])>32:
+				raise CatalystError,\
+					"ISO volume ID must not exceed 32 characters."
+		else:
+			self.settings["iso_volume_id"]="catalyst "+self.settings["snapshot"]
+
+	def set_action_sequence(self):
+		""" Default action sequence for run method """
+		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
+				"setup_confdir","portage_overlay",\
+				"base_dirs","bind","chroot_setup","setup_environment",\
+				"run_local","preclean","unbind","clean"]
+#		if "TARBALL" in self.settings or \
+#			"FETCH" not in self.settings:
+		if "FETCH" not in self.settings:
+			self.settings["action_sequence"].append("capture")
+		self.settings["action_sequence"].append("clear_autoresume")
+
+	def set_use(self):
+		if self.settings["spec_prefix"]+"/use" in self.settings:
+			self.settings["use"]=\
+				self.settings[self.settings["spec_prefix"]+"/use"]
+			del self.settings[self.settings["spec_prefix"]+"/use"]
+		if "use" not in self.settings:
+			self.settings["use"]=""
+		if type(self.settings["use"])==types.StringType:
+			self.settings["use"]=self.settings["use"].split()
+
+		# Force bindist when options ask for it
+		if "BINDIST" in self.settings:
+			self.settings["use"].append("bindist")
+
+	def set_stage_path(self):
+		self.settings["stage_path"]=normpath(self.settings["chroot_path"])
+
+	def set_mounts(self):
+		pass
+
+	def set_packages(self):
+		pass
+
+	def set_rm(self):
+		if self.settings["spec_prefix"]+"/rm" in self.settings:
+			if type(self.settings[self.settings["spec_prefix"]+\
+				"/rm"])==types.StringType:
+				self.settings[self.settings["spec_prefix"]+"/rm"]=\
+					self.settings[self.settings["spec_prefix"]+"/rm"].split()
+
+	def set_linuxrc(self):
+		if self.settings["spec_prefix"]+"/linuxrc" in self.settings:
+			if type(self.settings[self.settings["spec_prefix"]+\
+				"/linuxrc"])==types.StringType:
+				self.settings["linuxrc"]=\
+					self.settings[self.settings["spec_prefix"]+"/linuxrc"]
+				del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
+
+	def set_busybox_config(self):
+		if self.settings["spec_prefix"]+"/busybox_config" in self.settings:
+			if type(self.settings[self.settings["spec_prefix"]+\
+				"/busybox_config"])==types.StringType:
+				self.settings["busybox_config"]=\
+					self.settings[self.settings["spec_prefix"]+"/busybox_config"]
+				del self.settings[self.settings["spec_prefix"]+"/busybox_config"]
+
+	def set_portage_overlay(self):
+		if "portage_overlay" in self.settings:
+			if type(self.settings["portage_overlay"])==types.StringType:
+				self.settings["portage_overlay"]=\
+					self.settings["portage_overlay"].split()
+			print "portage_overlay directories are set to: \""+\
+				string.join(self.settings["portage_overlay"])+"\""
+
+	def set_overlay(self):
+		if self.settings["spec_prefix"]+"/overlay" in self.settings:
+			if type(self.settings[self.settings["spec_prefix"]+\
+				"/overlay"])==types.StringType:
+				self.settings[self.settings["spec_prefix"]+"/overlay"]=\
+					self.settings[self.settings["spec_prefix"]+\
+					"/overlay"].split()
+
+	def set_root_overlay(self):
+		if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
+			if type(self.settings[self.settings["spec_prefix"]+\
+				"/root_overlay"])==types.StringType:
+				self.settings[self.settings["spec_prefix"]+"/root_overlay"]=\
+					self.settings[self.settings["spec_prefix"]+\
+					"/root_overlay"].split()
+
+	def set_root_path(self):
+		""" ROOT= variable for emerges """
+		self.settings["root_path"]="/"
+
+	def set_valid_build_kernel_vars(self,addlargs):
+		if "boot/kernel" in addlargs:
+			if type(addlargs["boot/kernel"])==types.StringType:
+				loopy=[addlargs["boot/kernel"]]
+			else:
+				loopy=addlargs["boot/kernel"]
+
+			for x in loopy:
+				self.valid_values.append("boot/kernel/"+x+"/aliases")
+				self.valid_values.append("boot/kernel/"+x+"/config")
+				self.valid_values.append("boot/kernel/"+x+"/console")
+				self.valid_values.append("boot/kernel/"+x+"/extraversion")
+				self.valid_values.append("boot/kernel/"+x+"/gk_action")
+				self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
+				self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
+				self.valid_values.append("boot/kernel/"+x+"/machine_type")
+				self.valid_values.append("boot/kernel/"+x+"/sources")
+				self.valid_values.append("boot/kernel/"+x+"/softlevel")
+				self.valid_values.append("boot/kernel/"+x+"/use")
+				self.valid_values.append("boot/kernel/"+x+"/packages")
+				if "boot/kernel/"+x+"/packages" in addlargs:
+					if type(addlargs["boot/kernel/"+x+\
+						"/packages"])==types.StringType:
+						addlargs["boot/kernel/"+x+"/packages"]=\
+							[addlargs["boot/kernel/"+x+"/packages"]]
+
+	def set_build_kernel_vars(self):
+		if self.settings["spec_prefix"]+"/gk_mainargs" in self.settings:
+			self.settings["gk_mainargs"]=\
+				self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
+			del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
+
+	def kill_chroot_pids(self):
+		print "Checking for processes running in chroot and killing them."
+
+		"""
+		Force environment variables to be exported so script can see them
+		"""
+		self.setup_environment()
+
+		if os.path.exists(self.settings["sharedir"]+\
+			"/targets/support/kill-chroot-pids.sh"):
+			cmd("/bin/bash "+self.settings["sharedir"]+\
+				"/targets/support/kill-chroot-pids.sh",\
+				"kill-chroot-pids script failed.",env=self.env)
+
+	def mount_safety_check(self):
+		mypath=self.settings["chroot_path"]
+
+		"""
+		Check and verify that none of our paths in mypath are mounted. We don't
+		want to clean up with things still mounted, and this allows us to check.
+		Returns 1 on ok, 0 on "something is still mounted" case.
+		"""
+
+		if not os.path.exists(mypath):
+			return
+
+		for x in self.mounts:
+			if not os.path.exists(mypath + self.mountmap[x]):
+				continue
+
+			if ismount(mypath +self.mountmap[x]):
+				""" Something is still mounted "" """
+				try:
+					print self.mountmap[x] + " is still mounted; performing auto-bind-umount...",
+					""" Try to umount stuff ourselves """
+					self.unbind()
+					if ismount(mypath + self.mountmap[x]):
+						raise CatalystError, "Auto-unbind failed for " + self.mountmap[x]
+					else:
+						print "Auto-unbind successful..."
+				except CatalystError:
+					raise CatalystError, "Unable to auto-unbind " + self.mountmap[x]
+
+	def unpack(self):
+		unpack=True
+
+		clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+\
+			"unpack")
+
+		if "SEEDCACHE" in self.settings:
+			if os.path.isdir(self.settings["source_path"]):
+				""" SEEDCACHE Is a directory, use rsync """
+				unpack_cmd="rsync -a --delete "+self.settings["source_path"]+\
+					" "+self.settings["chroot_path"]
+				display_msg="\nStarting rsync from "+\
+					self.settings["source_path"]+"\nto "+\
+					self.settings["chroot_path"]+\
+					" (This may take some time) ...\n"
+				error_msg="Rsync of "+self.settings["source_path"]+" to "+\
+					self.settings["chroot_path"]+" failed."
+			else:
+				""" SEEDCACHE is a not a directory, try untar'ing """
+				print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
+				display_msg="\nStarting tar extract from "+\
+					self.settings["source_path"]+"\nto "+\
+					self.settings["chroot_path"]+\
+						" (This may take some time) ...\n"
+				if "bz2" == self.settings["chroot_path"][-3:]:
+					unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
+						self.settings["chroot_path"]
+				else:
+					unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
+						self.settings["chroot_path"]
+				error_msg="Tarball extraction of "+\
+					self.settings["source_path"]+" to "+\
+					self.settings["chroot_path"]+" failed."
+		else:
+			""" No SEEDCACHE, use tar """
+			display_msg="\nStarting tar extract from "+\
+				self.settings["source_path"]+"\nto "+\
+				self.settings["chroot_path"]+\
+				" (This may take some time) ...\n"
+			if "bz2" == self.settings["chroot_path"][-3:]:
+				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
+					self.settings["chroot_path"]
+			else:
+				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["source_path"]+" -C "+\
+					self.settings["chroot_path"]
+			error_msg="Tarball extraction of "+self.settings["source_path"]+\
+				" to "+self.settings["chroot_path"]+" failed."
+
+		if "AUTORESUME" in self.settings:
+			if os.path.isdir(self.settings["source_path"]) \
+				and os.path.exists(self.settings["autoresume_path"]+"unpack"):
+				""" Autoresume is valid, SEEDCACHE is valid """
+				unpack=False
+				invalid_snapshot=False
+
+			elif os.path.isfile(self.settings["source_path"]) \
+				and self.settings["source_path_hash"]==clst_unpack_hash:
+				""" Autoresume is valid, tarball is valid """
+				unpack=False
+				invalid_snapshot=True
+
+			elif os.path.isdir(self.settings["source_path"]) \
+				and not os.path.exists(self.settings["autoresume_path"]+\
+				"unpack"):
+				""" Autoresume is invalid, SEEDCACHE """
+				unpack=True
+				invalid_snapshot=False
+
+			elif os.path.isfile(self.settings["source_path"]) \
+				and self.settings["source_path_hash"]!=clst_unpack_hash:
+				""" Autoresume is invalid, tarball """
+				unpack=True
+				invalid_snapshot=True
+		else:
+			""" No autoresume, SEEDCACHE """
+			if "SEEDCACHE" in self.settings:
+				""" SEEDCACHE so let's run rsync and let it clean up """
+				if os.path.isdir(self.settings["source_path"]):
+					unpack=True
+					invalid_snapshot=False
+				elif os.path.isfile(self.settings["source_path"]):
+					""" Tarball so unpack and remove anything already there """
+					unpack=True
+					invalid_snapshot=True
+				""" No autoresume, no SEEDCACHE """
+			else:
+				""" Tarball so unpack and remove anything already there """
+				if os.path.isfile(self.settings["source_path"]):
+					unpack=True
+					invalid_snapshot=True
+				elif os.path.isdir(self.settings["source_path"]):
+					""" We should never reach this, so something is very wrong """
+					raise CatalystError,\
+						"source path is a dir but seedcache is not enabled"
+
+		if unpack:
+			self.mount_safety_check()
+
+			if invalid_snapshot:
+				if "AUTORESUME" in self.settings:
+					print "No Valid Resume point detected, cleaning up..."
+
+				self.clear_autoresume()
+				self.clear_chroot()
+
+			if not os.path.exists(self.settings["chroot_path"]):
+				os.makedirs(self.settings["chroot_path"])
+
+			if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
+				os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
+
+			if "PKGCACHE" in self.settings:
+				if not os.path.exists(self.settings["pkgcache_path"]):
+					os.makedirs(self.settings["pkgcache_path"],0755)
+
+			if "KERNCACHE" in self.settings:
+				if not os.path.exists(self.settings["kerncache_path"]):
+					os.makedirs(self.settings["kerncache_path"],0755)
+
+			print display_msg
+			cmd(unpack_cmd,error_msg,env=self.env)
+
+			if "source_path_hash" in self.settings:
+				myf=open(self.settings["autoresume_path"]+"unpack","w")
+				myf.write(self.settings["source_path_hash"])
+				myf.close()
+			else:
+				touch(self.settings["autoresume_path"]+"unpack")
+		else:
+			print "Resume point detected, skipping unpack operation..."
+
+	def unpack_snapshot(self):
+		unpack=True
+		snapshot_hash=read_from_clst(self.settings["autoresume_path"]+\
+			"unpack_portage")
+
+		if "SNAPCACHE" in self.settings:
+			snapshot_cache_hash=\
+				read_from_clst(self.settings["snapshot_cache_path"]+\
+				"catalyst-hash")
+			destdir=self.settings["snapshot_cache_path"]
+			if "bz2" == self.settings["chroot_path"][-3:]:
+				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+destdir
+			else:
+				unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+destdir
+			unpack_errmsg="Error unpacking snapshot"
+			cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+\
+				self.settings["snapshot_cache_path"]+\
+				" (This can take a long time)..."
+			cleanup_errmsg="Error removing existing snapshot cache directory."
+			self.snapshot_lock_object=self.snapcache_lock
+
+			if self.settings["snapshot_path_hash"]==snapshot_cache_hash:
+				print "Valid snapshot cache, skipping unpack of portage tree..."
+				unpack=False
+		else:
+			destdir=normpath(self.settings["chroot_path"] + self.settings["portdir"])
+			cleanup_errmsg="Error removing existing snapshot directory."
+			cleanup_msg=\
+				"Cleaning up existing portage tree (This can take a long time)..."
+			if "bz2" == self.settings["chroot_path"][-3:]:
+				unpack_cmd="tar -I lbzip2 -xpf "+self.settings["snapshot_path"]+" -C "+\
+					self.settings["chroot_path"]+"/usr"
+			else:
+				unpack_cmd="tar xpf "+self.settings["snapshot_path"]+" -C "+\
+					self.settings["chroot_path"]+"/usr"
+			unpack_errmsg="Error unpacking snapshot"
+
+			if "AUTORESUME" in self.settings \
+				and os.path.exists(self.settings["chroot_path"]+\
+					self.settings["portdir"]) \
+				and os.path.exists(self.settings["autoresume_path"]\
+					+"unpack_portage") \
+				and self.settings["snapshot_path_hash"] == snapshot_hash:
+					print \
+						"Valid Resume point detected, skipping unpack of portage tree..."
+					unpack=False
+
+		if unpack:
+			if "SNAPCACHE" in self.settings:
+				self.snapshot_lock_object.write_lock()
+			if os.path.exists(destdir):
+				print cleanup_msg
+				cleanup_cmd="rm -rf "+destdir
+				cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
+			if not os.path.exists(destdir):
+				os.makedirs(destdir,0755)
+
+			print "Unpacking portage tree (This can take a long time) ..."
+			cmd(unpack_cmd,unpack_errmsg,env=self.env)
+
+			if "SNAPCACHE" in self.settings:
+				myf=open(self.settings["snapshot_cache_path"]+"catalyst-hash","w")
+				myf.write(self.settings["snapshot_path_hash"])
+				myf.close()
+			else:
+				print "Setting snapshot autoresume point"
+				myf=open(self.settings["autoresume_path"]+"unpack_portage","w")
+				myf.write(self.settings["snapshot_path_hash"])
+				myf.close()
+
+			if "SNAPCACHE" in self.settings:
+				self.snapshot_lock_object.unlock()
+
+	def config_profile_link(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+\
+				"config_profile_link"):
+			print \
+				"Resume point detected, skipping config_profile_link operation..."
+		else:
+			# TODO: zmedico and I discussed making this a directory and pushing
+			# in a parent file, as well as other user-specified configuration.
+			print "Configuring profile link..."
+			cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.profile",\
+					"Error zapping profile link",env=self.env)
+			cmd("mkdir -p "+self.settings["chroot_path"]+"/etc/portage/")
+			cmd("ln -sf ../.." + self.settings["portdir"] + "/profiles/"+\
+				self.settings["target_profile"]+" "+\
+				self.settings["chroot_path"]+"/etc/portage/make.profile",\
+				"Error creating profile link",env=self.env)
+			touch(self.settings["autoresume_path"]+"config_profile_link")
+
+	def setup_confdir(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+\
+				"setup_confdir"):
+			print "Resume point detected, skipping setup_confdir operation..."
+		else:
+			if "portage_confdir" in self.settings:
+				print "Configuring /etc/portage..."
+				cmd("rsync -a "+self.settings["portage_confdir"]+"/ "+\
+					self.settings["chroot_path"]+"/etc/portage/",\
+					"Error copying /etc/portage",env=self.env)
+				touch(self.settings["autoresume_path"]+"setup_confdir")
+
+	def portage_overlay(self):
+		""" We copy the contents of our overlays to /usr/local/portage """
+		if "portage_overlay" in self.settings:
+			for x in self.settings["portage_overlay"]:
+				if os.path.exists(x):
+					print "Copying overlay dir " +x
+					cmd("mkdir -p "+self.settings["chroot_path"]+\
+						self.settings["local_overlay"],\
+						"Could not make portage_overlay dir",env=self.env)
+					cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+\
+						self.settings["local_overlay"],\
+						"Could not copy portage_overlay",env=self.env)
+
+	def root_overlay(self):
+		""" Copy over the root_overlay """
+		if self.settings["spec_prefix"]+"/root_overlay" in self.settings:
+			for x in self.settings[self.settings["spec_prefix"]+\
+				"/root_overlay"]:
+				if os.path.exists(x):
+					print "Copying root_overlay: "+x
+					cmd("rsync -a "+x+"/ "+\
+						self.settings["chroot_path"],\
+						self.settings["spec_prefix"]+"/root_overlay: "+x+\
+						" copy failed.",env=self.env)
+
+	def base_dirs(self):
+		pass
+
+	def bind(self):
+		for x in self.mounts:
+			if not os.path.exists(self.settings["chroot_path"] + self.mountmap[x]):
+				os.makedirs(self.settings["chroot_path"]+x,0755)
+
+			if not os.path.exists(self.mountmap[x]):
+				if not self.mountmap[x] == "tmpfs":
+					os.makedirs(self.mountmap[x],0755)
+
+			src=self.mountmap[x]
+			if "SNAPCACHE" in self.settings and x == "/usr/portage":
+				self.snapshot_lock_object.read_lock()
+			if os.uname()[0] == "FreeBSD":
+				if src == "/dev":
+					retval=os.system("mount -t devfs none " +
+						self.settings["chroot_path"] + src)
+				else:
+					retval=os.system("mount_nullfs " + src + " " +
+						self.settings["chroot_path"] + src)
+			else:
+				if src == "tmpfs":
+					if "var_tmpfs_portage" in self.settings:
+						retval=os.system("mount -t tmpfs -o size="+\
+							self.settings["var_tmpfs_portage"]+"G "+src+" "+\
+							self.settings["chroot_path"]+x)
+				else:
+					retval=os.system("mount --bind " + src + " " +
+						self.settings["chroot_path"] + src)
+			if retval!=0:
+				self.unbind()
+				raise CatalystError,"Couldn't bind mount " + src
+
+	def unbind(self):
+		ouch=0
+		mypath=self.settings["chroot_path"]
+		myrevmounts=self.mounts[:]
+		myrevmounts.reverse()
+		""" Unmount in reverse order for nested bind-mounts """
+		for x in myrevmounts:
+			if not os.path.exists(mypath + self.mountmap[x]):
+				continue
+
+			if not ismount(mypath + self.mountmap[x]):
+				continue
+
+			retval=os.system("umount "+\
+				os.path.join(mypath, self.mountmap[x].lstrip(os.path.sep)))
+
+			if retval!=0:
+				warn("First attempt to unmount: " + mypath +
+					self.mountmap[x] +" failed.")
+				warn("Killing any pids still running in the chroot")
+
+				self.kill_chroot_pids()
+
+				retval2=os.system("umount " + mypath + self.mountmap[x])
+				if retval2!=0:
+					ouch=1
+					warn("Couldn't umount bind mount: " + mypath + self.mountmap[x])
+
+			if "SNAPCACHE" in self.settings and x == "/usr/portage":
+				try:
+					"""
+					It's possible the snapshot lock object isn't created yet.
+					This is because mount safety check calls unbind before the
+					target is fully initialized
+					"""
+					self.snapshot_lock_object.unlock()
+				except:
+					pass
+		if ouch:
+			"""
+			if any bind mounts really failed, then we need to raise
+			this to potentially prevent an upcoming bash stage cleanup script
+			from wiping our bind mounts.
+			"""
+			raise CatalystError,\
+				"Couldn't umount one or more bind-mounts; aborting for safety."
+
+	def chroot_setup(self):
+		self.makeconf=read_makeconf(self.settings["chroot_path"]+\
+			"/etc/portage/make.conf")
+		self.override_cbuild()
+		self.override_chost()
+		self.override_cflags()
+		self.override_cxxflags()
+		self.override_ldflags()
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"chroot_setup"):
+			print "Resume point detected, skipping chroot_setup operation..."
+		else:
+			print "Setting up chroot..."
+
+			#self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/portage/make.conf")
+
+			cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
+				"Could not copy resolv.conf into place.",env=self.env)
+
+			""" Copy over the envscript, if applicable """
+			if "ENVSCRIPT" in self.settings:
+				if not os.path.exists(self.settings["ENVSCRIPT"]):
+					raise CatalystError,\
+						"Can't find envscript "+self.settings["ENVSCRIPT"]
+
+				print "\nWarning!!!!"
+				print "\tOverriding certain env variables may cause catastrophic failure."
+				print "\tIf your build fails look here first as the possible problem."
+				print "\tCatalyst assumes you know what you are doing when setting"
+				print "\t\tthese variables."
+				print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
+				print "\tYou have been warned\n"
+
+				cmd("cp "+self.settings["ENVSCRIPT"]+" "+\
+					self.settings["chroot_path"]+"/tmp/envscript",\
+					"Could not copy envscript into place.",env=self.env)
+
+			"""
+			Copy over /etc/hosts from the host in case there are any
+			specialties in there
+			"""
+			if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
+				cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+\
+					self.settings["chroot_path"]+"/etc/hosts.catalyst",\
+					"Could not backup /etc/hosts",env=self.env)
+				cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts",\
+					"Could not copy /etc/hosts",env=self.env)
+
+			""" Modify and write out make.conf (for the chroot) """
+			cmd("rm -f "+self.settings["chroot_path"]+"/etc/portage/make.conf",\
+				"Could not remove "+self.settings["chroot_path"]+\
+				"/etc/portage/make.conf",env=self.env)
+			myf=open(self.settings["chroot_path"]+"/etc/portage/make.conf","w")
+			myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
+			myf.write("# Please consult /usr/share/portage/config/make.conf.example for a more\n# detailed example.\n")
+			if "CFLAGS" in self.settings:
+				myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
+			if "CXXFLAGS" in self.settings:
+				if self.settings["CXXFLAGS"]!=self.settings["CFLAGS"]:
+					myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
+				else:
+					myf.write('CXXFLAGS="${CFLAGS}"\n')
+			else:
+				myf.write('CXXFLAGS="${CFLAGS}"\n')
+
+			if "LDFLAGS" in self.settings:
+				myf.write("# LDFLAGS is unsupported.  USE AT YOUR OWN RISK!\n")
+				myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
+			if "CBUILD" in self.settings:
+				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")
+				myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
+
+			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")
+			myf.write('CHOST="'+self.settings["CHOST"]+'"\n')
+
+			""" Figure out what our USE vars are for building """
+			myusevars=[]
+			if "HOSTUSE" in self.settings:
+				myusevars.extend(self.settings["HOSTUSE"])
+
+			if "use" in self.settings:
+				myusevars.extend(self.settings["use"])
+
+			if myusevars:
+				myf.write("# These are the USE flags that were used in addition to what is provided by the\n# profile used for building.\n")
+				myusevars = sorted(set(myusevars))
+				myf.write('USE="'+string.join(myusevars)+'"\n')
+				if '-*' in myusevars:
+					print "\nWarning!!!  "
+					print "\tThe use of -* in "+self.settings["spec_prefix"]+\
+						"/use will cause portage to ignore"
+					print "\tpackage.use in the profile and portage_confdir. You've been warned!"
+
+			myf.write('PORTDIR="%s"\n' % self.settings['portdir'])
+			myf.write('DISTDIR="%s"\n' % self.settings['distdir'])
+			myf.write('PKGDIR="%s"\n' % self.settings['packagedir'])
+
+			""" Setup the portage overlay """
+			if "portage_overlay" in self.settings:
+				myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
+
+			myf.close()
+			cmd("cp "+self.settings["chroot_path"]+"/etc/portage/make.conf "+\
+				self.settings["chroot_path"]+"/etc/portage/make.conf.catalyst",\
+				"Could not backup /etc/portage/make.conf",env=self.env)
+			touch(self.settings["autoresume_path"]+"chroot_setup")
+
+	def fsscript(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
+			print "Resume point detected, skipping fsscript operation..."
+		else:
+			if "fsscript" in self.settings:
+				if os.path.exists(self.settings["controller_file"]):
+					cmd("/bin/bash "+self.settings["controller_file"]+\
+						" fsscript","fsscript script failed.",env=self.env)
+					touch(self.settings["autoresume_path"]+"fsscript")
+
+	def rcupdate(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
+			print "Resume point detected, skipping rcupdate operation..."
+		else:
+			if os.path.exists(self.settings["controller_file"]):
+				cmd("/bin/bash "+self.settings["controller_file"]+" rc-update",\
+					"rc-update script failed.",env=self.env)
+				touch(self.settings["autoresume_path"]+"rcupdate")
+
+	def clean(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"clean"):
+			print "Resume point detected, skipping clean operation..."
+		else:
+			for x in self.settings["cleanables"]:
+				print "Cleaning chroot: "+x+"... "
+				cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+\
+					x,env=self.env)
+
+		""" Put /etc/hosts back into place """
+		if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.catalyst"):
+			cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.catalyst "+\
+				self.settings["chroot_path"]+"/etc/hosts",\
+				"Could not replace /etc/hosts",env=self.env)
+
+		""" Remove our overlay """
+		if os.path.exists(self.settings["chroot_path"] + self.settings["local_overlay"]):
+			cmd("rm -rf " + self.settings["chroot_path"] + self.settings["local_overlay"],
+				"Could not remove " + self.settings["local_overlay"], env=self.env)
+			cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+\
+				"/etc/portage/make.conf",\
+				"Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
+
+		""" Clean up old and obsoleted files in /etc """
+		if os.path.exists(self.settings["stage_path"]+"/etc"):
+			cmd("find "+self.settings["stage_path"]+\
+				"/etc -maxdepth 1 -name \"*-\" | xargs rm -f",\
+				"Could not remove stray files in /etc",env=self.env)
+
+		if os.path.exists(self.settings["controller_file"]):
+			cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
+				"clean script failed.",env=self.env)
+			touch(self.settings["autoresume_path"]+"clean")
+
+	def empty(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"empty"):
+			print "Resume point detected, skipping empty operation..."
+		else:
+			if self.settings["spec_prefix"]+"/empty" in self.settings:
+				if type(self.settings[self.settings["spec_prefix"]+\
+					"/empty"])==types.StringType:
+					self.settings[self.settings["spec_prefix"]+"/empty"]=\
+						self.settings[self.settings["spec_prefix"]+\
+						"/empty"].split()
+				for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
+					myemp=self.settings["destpath"]+x
+					if not os.path.isdir(myemp) or os.path.islink(myemp):
+						print x,"not a directory or does not exist, skipping 'empty' operation."
+						continue
+					print "Emptying directory",x
+					"""
+					stat the dir, delete the dir, recreate the dir and set
+					the proper perms and ownership
+					"""
+					mystat=os.stat(myemp)
+					shutil.rmtree(myemp)
+					os.makedirs(myemp,0755)
+					os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
+					os.chmod(myemp,mystat[ST_MODE])
+			touch(self.settings["autoresume_path"]+"empty")
+
+	def remove(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"remove"):
+			print "Resume point detected, skipping remove operation..."
+		else:
+			if self.settings["spec_prefix"]+"/rm" in self.settings:
+				for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
+					"""
+					We're going to shell out for all these cleaning
+					operations, so we get easy glob handling.
+					"""
+					print "livecd: removing "+x
+					os.system("rm -rf "+self.settings["chroot_path"]+x)
+				try:
+					if os.path.exists(self.settings["controller_file"]):
+						cmd("/bin/bash "+self.settings["controller_file"]+\
+							" clean","Clean  failed.",env=self.env)
+						touch(self.settings["autoresume_path"]+"remove")
+				except:
+					self.unbind()
+					raise
+
+	def preclean(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"preclean"):
+			print "Resume point detected, skipping preclean operation..."
+		else:
+			try:
+				if os.path.exists(self.settings["controller_file"]):
+					cmd("/bin/bash "+self.settings["controller_file"]+\
+						" preclean","preclean script failed.",env=self.env)
+					touch(self.settings["autoresume_path"]+"preclean")
+
+			except:
+				self.unbind()
+				raise CatalystError, "Build failed, could not execute preclean"
+
+	def capture(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"capture"):
+			print "Resume point detected, skipping capture operation..."
+		else:
+			""" Capture target in a tarball """
+			mypath=self.settings["target_path"].split("/")
+			""" Remove filename from path """
+			mypath=string.join(mypath[:-1],"/")
+
+			""" Now make sure path exists """
+			if not os.path.exists(mypath):
+				os.makedirs(mypath)
+
+			print "Creating stage tarball..."
+
+			cmd("tar -I lbzip2 -cpf "+self.settings["target_path"]+" -C "+\
+				self.settings["stage_path"]+" .",\
+				"Couldn't create stage tarball",env=self.env)
+
+			self.gen_contents_file(self.settings["target_path"])
+			self.gen_digest_file(self.settings["target_path"])
+
+			touch(self.settings["autoresume_path"]+"capture")
+
+	def run_local(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"run_local"):
+			print "Resume point detected, skipping run_local operation..."
+		else:
+			try:
+				if os.path.exists(self.settings["controller_file"]):
+					cmd("/bin/bash "+self.settings["controller_file"]+" run",\
+						"run script failed.",env=self.env)
+					touch(self.settings["autoresume_path"]+"run_local")
+
+			except CatalystError:
+				self.unbind()
+				raise CatalystError,"Stage build aborting due to error."
+
+	def setup_environment(self):
+		"""
+		Modify the current environment. This is an ugly hack that should be
+		fixed. We need this to use the os.system() call since we can't
+		specify our own environ
+		"""
+		for x in self.settings.keys():
+			""" Sanitize var names by doing "s|/-.|_|g" """
+			varname="clst_"+string.replace(x,"/","_")
+			varname=string.replace(varname,"-","_")
+			varname=string.replace(varname,".","_")
+			if type(self.settings[x])==types.StringType:
+				""" Prefix to prevent namespace clashes """
+				#os.environ[varname]=self.settings[x]
+				self.env[varname]=self.settings[x]
+			elif type(self.settings[x])==types.ListType:
+				#os.environ[varname]=string.join(self.settings[x])
+				self.env[varname]=string.join(self.settings[x])
+			elif type(self.settings[x])==types.BooleanType:
+				if self.settings[x]:
+					self.env[varname]="true"
+				else:
+					self.env[varname]="false"
+		if "makeopts" in self.settings:
+			self.env["MAKEOPTS"]=self.settings["makeopts"]
+
+	def run(self):
+		self.chroot_lock.write_lock()
+
+		""" Kill any pids in the chroot "" """
+		self.kill_chroot_pids()
+
+		""" Check for mounts right away and abort if we cannot unmount them """
+		self.mount_safety_check()
+
+		if "CLEAR_AUTORESUME" in self.settings:
+			self.clear_autoresume()
+
+		if "PURGETMPONLY" in self.settings:
+			self.purge()
+			return
+
+		if "PURGEONLY" in self.settings:
+			self.purge()
+			return
+
+		if "PURGE" in self.settings:
+			self.purge()
+
+		for x in self.settings["action_sequence"]:
+			print "--- Running action sequence: "+x
+			sys.stdout.flush()
+			try:
+				apply(getattr(self,x))
+			except:
+				self.mount_safety_check()
+				raise
+
+		self.chroot_lock.unlock()
+
+	def unmerge(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
+			print "Resume point detected, skipping unmerge operation..."
+		else:
+			if self.settings["spec_prefix"]+"/unmerge" in self.settings:
+				if type(self.settings[self.settings["spec_prefix"]+\
+					"/unmerge"])==types.StringType:
+					self.settings[self.settings["spec_prefix"]+"/unmerge"]=\
+						[self.settings[self.settings["spec_prefix"]+"/unmerge"]]
+				myunmerge=\
+					self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
+
+				for x in range(0,len(myunmerge)):
+					"""
+					Surround args with quotes for passing to bash, allows
+					things like "<" to remain intact
+					"""
+					myunmerge[x]="'"+myunmerge[x]+"'"
+				myunmerge=string.join(myunmerge)
+
+				""" Before cleaning, unmerge stuff """
+				try:
+					cmd("/bin/bash "+self.settings["controller_file"]+\
+						" unmerge "+ myunmerge,"Unmerge script failed.",\
+						env=self.env)
+					print "unmerge shell script"
+				except CatalystError:
+					self.unbind()
+					raise
+				touch(self.settings["autoresume_path"]+"unmerge")
+
+	def target_setup(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
+			print "Resume point detected, skipping target_setup operation..."
+		else:
+			print "Setting up filesystems per filesystem type"
+			cmd("/bin/bash "+self.settings["controller_file"]+\
+				" target_image_setup "+ self.settings["target_path"],\
+				"target_image_setup script failed.",env=self.env)
+			touch(self.settings["autoresume_path"]+"target_setup")
+
+	def setup_overlay(self):
+		if "AUTORESUME" in self.settings \
+		and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
+			print "Resume point detected, skipping setup_overlay operation..."
+		else:
+			if self.settings["spec_prefix"]+"/overlay" in self.settings:
+				for x in self.settings[self.settings["spec_prefix"]+"/overlay"]:
+					if os.path.exists(x):
+						cmd("rsync -a "+x+"/ "+\
+							self.settings["target_path"],\
+							self.settings["spec_prefix"]+"overlay: "+x+\
+							" copy failed.",env=self.env)
+				touch(self.settings["autoresume_path"]+"setup_overlay")
+
+	def create_iso(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
+			print "Resume point detected, skipping create_iso operation..."
+		else:
+			""" Create the ISO """
+			if "iso" in self.settings:
+				cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
+					self.settings["iso"],"ISO creation script failed.",\
+					env=self.env)
+				self.gen_contents_file(self.settings["iso"])
+				self.gen_digest_file(self.settings["iso"])
+				touch(self.settings["autoresume_path"]+"create_iso")
+			else:
+				print "WARNING: livecd/iso was not defined."
+				print "An ISO Image will not be created."
+
+	def build_packages(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+\
+				"build_packages"):
+			print "Resume point detected, skipping build_packages operation..."
+		else:
+			if self.settings["spec_prefix"]+"/packages" in self.settings:
+				if "AUTORESUME" in self.settings \
+					and os.path.exists(self.settings["autoresume_path"]+\
+						"build_packages"):
+					print "Resume point detected, skipping build_packages operation..."
+				else:
+					mypack=\
+						list_bashify(self.settings[self.settings["spec_prefix"]\
+						+"/packages"])
+					try:
+						cmd("/bin/bash "+self.settings["controller_file"]+\
+							" build_packages "+mypack,\
+							"Error in attempt to build packages",env=self.env)
+						touch(self.settings["autoresume_path"]+"build_packages")
+					except CatalystError:
+						self.unbind()
+						raise CatalystError,self.settings["spec_prefix"]+\
+							"build aborting due to error."
+
+	def build_kernel(self):
+		"Build all configured kernels"
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
+			print "Resume point detected, skipping build_kernel operation..."
+		else:
+			if "boot/kernel" in self.settings:
+				try:
+					mynames=self.settings["boot/kernel"]
+					if type(mynames)==types.StringType:
+						mynames=[mynames]
+					"""
+					Execute the script that sets up the kernel build environment
+					"""
+					cmd("/bin/bash "+self.settings["controller_file"]+\
+						" pre-kmerge ","Runscript pre-kmerge failed",\
+						env=self.env)
+					for kname in mynames:
+						self._build_kernel(kname=kname)
+					touch(self.settings["autoresume_path"]+"build_kernel")
+				except CatalystError:
+					self.unbind()
+					raise CatalystError,\
+						"build aborting due to kernel build error."
+
+	def _build_kernel(self, kname):
+		"Build a single configured kernel by name"
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]\
+				+"build_kernel_"+kname):
+			print "Resume point detected, skipping build_kernel for "+kname+" operation..."
+			return
+		self._copy_kernel_config(kname=kname)
+
+		"""
+		If we need to pass special options to the bootloader
+		for this kernel put them into the environment
+		"""
+		if "boot/kernel/"+kname+"/kernelopts" in self.settings:
+			myopts=self.settings["boot/kernel/"+kname+\
+				"/kernelopts"]
+
+			if type(myopts) != types.StringType:
+				myopts = string.join(myopts)
+				self.env[kname+"_kernelopts"]=myopts
+
+			else:
+				self.env[kname+"_kernelopts"]=""
+
+		if "boot/kernel/"+kname+"/extraversion" not in self.settings:
+			self.settings["boot/kernel/"+kname+\
+				"/extraversion"]=""
+
+		self.env["clst_kextraversion"]=\
+			self.settings["boot/kernel/"+kname+\
+			"/extraversion"]
+
+		self._copy_initramfs_overlay(kname=kname)
+
+		""" Execute the script that builds the kernel """
+		cmd("/bin/bash "+self.settings["controller_file"]+\
+			" kernel "+kname,\
+			"Runscript kernel build failed",env=self.env)
+
+		if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
+			if os.path.exists(self.settings["chroot_path"]+\
+				"/tmp/initramfs_overlay/"):
+				print "Cleaning up temporary overlay dir"
+				cmd("rm -R "+self.settings["chroot_path"]+\
+					"/tmp/initramfs_overlay/",env=self.env)
+
+		touch(self.settings["autoresume_path"]+\
+			"build_kernel_"+kname)
+
+		"""
+		Execute the script that cleans up the kernel build
+		environment
+		"""
+		cmd("/bin/bash "+self.settings["controller_file"]+\
+			" post-kmerge ",
+			"Runscript post-kmerge failed",env=self.env)
+
+	def _copy_kernel_config(self, kname):
+		if "boot/kernel/"+kname+"/config" in self.settings:
+			if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
+				self.unbind()
+				raise CatalystError,\
+					"Can't find kernel config: "+\
+					self.settings["boot/kernel/"+kname+\
+					"/config"]
+
+			try:
+				cmd("cp "+self.settings["boot/kernel/"+kname+\
+					"/config"]+" "+\
+					self.settings["chroot_path"]+"/var/tmp/"+\
+					kname+".config",\
+					"Couldn't copy kernel config: "+\
+					self.settings["boot/kernel/"+kname+\
+					"/config"],env=self.env)
+
+			except CatalystError:
+				self.unbind()
+
+	def _copy_initramfs_overlay(self, kname):
+		if "boot/kernel/"+kname+"/initramfs_overlay" in self.settings:
+			if os.path.exists(self.settings["boot/kernel/"+\
+				kname+"/initramfs_overlay"]):
+				print "Copying initramfs_overlay dir "+\
+					self.settings["boot/kernel/"+kname+\
+					"/initramfs_overlay"]
+
+				cmd("mkdir -p "+\
+					self.settings["chroot_path"]+\
+					"/tmp/initramfs_overlay/"+\
+					self.settings["boot/kernel/"+kname+\
+					"/initramfs_overlay"],env=self.env)
+
+				cmd("cp -R "+self.settings["boot/kernel/"+\
+					kname+"/initramfs_overlay"]+"/* "+\
+					self.settings["chroot_path"]+\
+					"/tmp/initramfs_overlay/"+\
+					self.settings["boot/kernel/"+kname+\
+					"/initramfs_overlay"],env=self.env)
+
+	def bootloader(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
+			print "Resume point detected, skipping bootloader operation..."
+		else:
+			try:
+				cmd("/bin/bash "+self.settings["controller_file"]+\
+					" bootloader " + self.settings["target_path"],\
+					"Bootloader script failed.",env=self.env)
+				touch(self.settings["autoresume_path"]+"bootloader")
+			except CatalystError:
+				self.unbind()
+				raise CatalystError,"Script aborting due to error."
+
+	def livecd_update(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+\
+				"livecd_update"):
+			print "Resume point detected, skipping build_packages operation..."
+		else:
+			try:
+				cmd("/bin/bash "+self.settings["controller_file"]+\
+					" livecd-update","livecd-update failed.",env=self.env)
+				touch(self.settings["autoresume_path"]+"livecd_update")
+
+			except CatalystError:
+				self.unbind()
+				raise CatalystError,"build aborting due to livecd_update error."
+
+	def clear_chroot(self):
+		myemp=self.settings["chroot_path"]
+		if os.path.isdir(myemp):
+			print "Emptying directory",myemp
+			"""
+			stat the dir, delete the dir, recreate the dir and set
+			the proper perms and ownership
+			"""
+			mystat=os.stat(myemp)
+			#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
+			""" There's no easy way to change flags recursively in python """
+			if os.uname()[0] == "FreeBSD":
+				os.system("chflags -R noschg "+myemp)
+			shutil.rmtree(myemp)
+			os.makedirs(myemp,0755)
+			os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
+			os.chmod(myemp,mystat[ST_MODE])
+
+	def clear_packages(self):
+		if "PKGCACHE" in self.settings:
+			print "purging the pkgcache ..."
+
+			myemp=self.settings["pkgcache_path"]
+			if os.path.isdir(myemp):
+				print "Emptying directory",myemp
+				"""
+				stat the dir, delete the dir, recreate the dir and set
+				the proper perms and ownership
+				"""
+				mystat=os.stat(myemp)
+				#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
+				shutil.rmtree(myemp)
+				os.makedirs(myemp,0755)
+				os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
+				os.chmod(myemp,mystat[ST_MODE])
+
+	def clear_kerncache(self):
+		if "KERNCACHE" in self.settings:
+			print "purging the kerncache ..."
+
+			myemp=self.settings["kerncache_path"]
+			if os.path.isdir(myemp):
+				print "Emptying directory",myemp
+				"""
+				stat the dir, delete the dir, recreate the dir and set
+				the proper perms and ownership
+				"""
+				mystat=os.stat(myemp)
+				#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
+				shutil.rmtree(myemp)
+				os.makedirs(myemp,0755)
+				os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
+				os.chmod(myemp,mystat[ST_MODE])
+
+	def clear_autoresume(self):
+		""" Clean resume points since they are no longer needed """
+		if "AUTORESUME" in self.settings:
+			print "Removing AutoResume Points: ..."
+		myemp=self.settings["autoresume_path"]
+		if os.path.isdir(myemp):
+				if "AUTORESUME" in self.settings:
+					print "Emptying directory",myemp
+				"""
+				stat the dir, delete the dir, recreate the dir and set
+				the proper perms and ownership
+				"""
+				mystat=os.stat(myemp)
+				if os.uname()[0] == "FreeBSD":
+					cmd("chflags -R noschg "+myemp,\
+						"Could not remove immutable flag for file "\
+						+myemp)
+				#cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
+				shutil.rmtree(myemp)
+				os.makedirs(myemp,0755)
+				os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
+				os.chmod(myemp,mystat[ST_MODE])
+
+	def gen_contents_file(self,file):
+		if os.path.exists(file+".CONTENTS"):
+			os.remove(file+".CONTENTS")
+		if "contents" in self.settings:
+			if os.path.exists(file):
+				myf=open(file+".CONTENTS","w")
+				keys={}
+				for i in self.settings["contents"].split():
+					keys[i]=1
+					array=keys.keys()
+					array.sort()
+				for j in array:
+					contents=generate_contents(file,contents_function=j,\
+						verbose="VERBOSE" in self.settings)
+					if contents:
+						myf.write(contents)
+				myf.close()
+
+	def gen_digest_file(self,file):
+		if os.path.exists(file+".DIGESTS"):
+			os.remove(file+".DIGESTS")
+		if "digests" in self.settings:
+			if os.path.exists(file):
+				myf=open(file+".DIGESTS","w")
+				keys={}
+				for i in self.settings["digests"].split():
+					keys[i]=1
+					array=keys.keys()
+					array.sort()
+				for f in [file, file+'.CONTENTS']:
+					if os.path.exists(f):
+						if "all" in array:
+							for k in hash_map.keys():
+								hash=generate_hash(f,hash_function=k,verbose=\
+									"VERBOSE" in self.settings)
+								myf.write(hash)
+						else:
+							for j in array:
+								hash=generate_hash(f,hash_function=j,verbose=\
+									"VERBOSE" in self.settings)
+								myf.write(hash)
+				myf.close()
+
+	def purge(self):
+		countdown(10,"Purging Caches ...")
+		if any(k in self.settings for k in ("PURGE","PURGEONLY","PURGETMPONLY")):
+			print "clearing autoresume ..."
+			self.clear_autoresume()
+
+			print "clearing chroot ..."
+			self.clear_chroot()
+
+			if "PURGETMPONLY" not in self.settings:
+				print "clearing package cache ..."
+				self.clear_packages()
+
+			print "clearing kerncache ..."
+			self.clear_kerncache()
+
+# vim: ts=4 sw=4 sta et sts=4 ai
diff --git a/catalyst/targets/generic_target.py b/catalyst/targets/generic_target.py
new file mode 100644
index 0000000..de51994
--- /dev/null
+++ b/catalyst/targets/generic_target.py
@@ -0,0 +1,11 @@
+from catalyst.support import *
+
+class generic_target:
+	"""
+	The toplevel class for generic_stage_target. This is about as generic as we get.
+	"""
+	def __init__(self,myspec,addlargs):
+		addl_arg_parse(myspec,addlargs,self.required_values,self.valid_values)
+		self.settings=myspec
+		self.env={}
+		self.env["PATH"]="/bin:/sbin:/usr/bin:/usr/sbin"
diff --git a/catalyst/targets/grp_target.py b/catalyst/targets/grp_target.py
new file mode 100644
index 0000000..8e70042
--- /dev/null
+++ b/catalyst/targets/grp_target.py
@@ -0,0 +1,118 @@
+"""
+Gentoo Reference Platform (GRP) target
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+import os,types,glob
+from catalyst.support import *
+from generic_stage_target import *
+
+class grp_target(generic_stage_target):
+	"""
+	The builder class for GRP (Gentoo Reference Platform) builds.
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=["version_stamp","target","subarch",\
+			"rel_type","profile","snapshot","source_subpath"]
+
+		self.valid_values=self.required_values[:]
+		self.valid_values.extend(["grp/use"])
+		if "grp" not in addlargs:
+			raise CatalystError,"Required value \"grp\" not specified in spec."
+
+		self.required_values.extend(["grp"])
+		if type(addlargs["grp"])==types.StringType:
+			addlargs["grp"]=[addlargs["grp"]]
+
+		if "grp/use" in addlargs:
+			if type(addlargs["grp/use"])==types.StringType:
+				addlargs["grp/use"]=[addlargs["grp/use"]]
+
+		for x in addlargs["grp"]:
+			self.required_values.append("grp/"+x+"/packages")
+			self.required_values.append("grp/"+x+"/type")
+
+		generic_stage_target.__init__(self,spec,addlargs)
+
+	def set_target_path(self):
+		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["target_subpath"]+"/")
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
+			print "Resume point detected, skipping target path setup operation..."
+		else:
+			# first clean up any existing target stuff
+			#if os.path.isdir(self.settings["target_path"]):
+				#cmd("rm -rf "+self.settings["target_path"],
+				#"Could not remove existing directory: "+self.settings["target_path"],env=self.env)
+			if not os.path.exists(self.settings["target_path"]):
+				os.makedirs(self.settings["target_path"])
+
+			touch(self.settings["autoresume_path"]+"setup_target_path")
+
+	def run_local(self):
+		for pkgset in self.settings["grp"]:
+			# example call: "grp.sh run pkgset cd1 xmms vim sys-apps/gleep"
+			mypackages=list_bashify(self.settings["grp/"+pkgset+"/packages"])
+			try:
+				cmd("/bin/bash "+self.settings["controller_file"]+" run "+self.settings["grp/"+pkgset+"/type"]\
+					+" "+pkgset+" "+mypackages,env=self.env)
+
+			except CatalystError:
+				self.unbind()
+				raise CatalystError,"GRP build aborting due to error."
+
+	def set_use(self):
+		generic_stage_target.set_use(self)
+		if "BINDIST" in self.settings:
+			if "use" in self.settings:
+				self.settings["use"].append("bindist")
+			else:
+				self.settings["use"]=["bindist"]
+
+	def set_mounts(self):
+	    self.mounts.append("/tmp/grp")
+            self.mountmap["/tmp/grp"]=self.settings["target_path"]
+
+	def generate_digests(self):
+		for pkgset in self.settings["grp"]:
+			if self.settings["grp/"+pkgset+"/type"] == "pkgset":
+				destdir=normpath(self.settings["target_path"]+"/"+pkgset+"/All")
+				print "Digesting files in the pkgset....."
+				digests=glob.glob(destdir+'/*.DIGESTS')
+				for i in digests:
+					if os.path.exists(i):
+						os.remove(i)
+
+				files=os.listdir(destdir)
+				#ignore files starting with '.' using list comprehension
+				files=[filename for filename in files if filename[0] != '.']
+				for i in files:
+					if os.path.isfile(normpath(destdir+"/"+i)):
+						self.gen_contents_file(normpath(destdir+"/"+i))
+						self.gen_digest_file(normpath(destdir+"/"+i))
+			else:
+				destdir=normpath(self.settings["target_path"]+"/"+pkgset)
+				print "Digesting files in the srcset....."
+
+				digests=glob.glob(destdir+'/*.DIGESTS')
+				for i in digests:
+					if os.path.exists(i):
+						os.remove(i)
+
+				files=os.listdir(destdir)
+				#ignore files starting with '.' using list comprehension
+				files=[filename for filename in files if filename[0] != '.']
+				for i in files:
+					if os.path.isfile(normpath(destdir+"/"+i)):
+						#self.gen_contents_file(normpath(destdir+"/"+i))
+						self.gen_digest_file(normpath(destdir+"/"+i))
+
+	def set_action_sequence(self):
+	    self.settings["action_sequence"]=["unpack","unpack_snapshot",\
+					"config_profile_link","setup_confdir","portage_overlay","bind","chroot_setup",\
+					"setup_environment","run_local","unbind",\
+					"generate_digests","clear_autoresume"]
+
+def register(foo):
+	foo.update({"grp":grp_target})
+	return foo
diff --git a/catalyst/targets/livecd_stage1_target.py b/catalyst/targets/livecd_stage1_target.py
new file mode 100644
index 0000000..ac846ec
--- /dev/null
+++ b/catalyst/targets/livecd_stage1_target.py
@@ -0,0 +1,75 @@
+"""
+LiveCD stage1 target
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+from catalyst.support import *
+from generic_stage_target import *
+
+class livecd_stage1_target(generic_stage_target):
+	"""
+	Builder class for LiveCD stage1.
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=["livecd/packages"]
+		self.valid_values=self.required_values[:]
+
+		self.valid_values.extend(["livecd/use"])
+		generic_stage_target.__init__(self,spec,addlargs)
+
+	def set_action_sequence(self):
+		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
+					"config_profile_link","setup_confdir","portage_overlay",\
+					"bind","chroot_setup","setup_environment","build_packages",\
+					"unbind", "clean","clear_autoresume"]
+
+	def set_target_path(self):
+		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["target_subpath"])
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
+				print "Resume point detected, skipping target path setup operation..."
+		else:
+			# first clean up any existing target stuff
+			if os.path.exists(self.settings["target_path"]):
+				cmd("rm -rf "+self.settings["target_path"],\
+					"Could not remove existing directory: "+self.settings["target_path"],env=self.env)
+				touch(self.settings["autoresume_path"]+"setup_target_path")
+
+			if not os.path.exists(self.settings["target_path"]):
+				os.makedirs(self.settings["target_path"])
+
+	def set_target_path(self):
+		pass
+
+	def set_spec_prefix(self):
+	                self.settings["spec_prefix"]="livecd"
+
+	def set_use(self):
+		generic_stage_target.set_use(self)
+		if "use" in self.settings:
+			self.settings["use"].append("livecd")
+			if "BINDIST" in self.settings:
+				self.settings["use"].append("bindist")
+		else:
+			self.settings["use"]=["livecd"]
+			if "BINDIST" in self.settings:
+				self.settings["use"].append("bindist")
+
+	def set_packages(self):
+		generic_stage_target.set_packages(self)
+		if self.settings["spec_prefix"]+"/packages" in self.settings:
+			if type(self.settings[self.settings["spec_prefix"]+"/packages"]) == types.StringType:
+				self.settings[self.settings["spec_prefix"]+"/packages"] = \
+					self.settings[self.settings["spec_prefix"]+"/packages"].split()
+		self.settings[self.settings["spec_prefix"]+"/packages"].append("app-misc/livecd-tools")
+
+	def set_pkgcache_path(self):
+		if "pkgcache_path" in self.settings:
+			if type(self.settings["pkgcache_path"]) != types.StringType:
+				self.settings["pkgcache_path"]=normpath(string.join(self.settings["pkgcache_path"]))
+		else:
+			generic_stage_target.set_pkgcache_path(self)
+
+def register(foo):
+	foo.update({"livecd-stage1":livecd_stage1_target})
+	return foo
diff --git a/catalyst/targets/livecd_stage2_target.py b/catalyst/targets/livecd_stage2_target.py
new file mode 100644
index 0000000..1bfd820
--- /dev/null
+++ b/catalyst/targets/livecd_stage2_target.py
@@ -0,0 +1,146 @@
+"""
+LiveCD stage2 target, builds upon previous LiveCD stage1 tarball
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+import os,string,types,stat,shutil
+from catalyst.support import *
+from generic_stage_target import *
+
+class livecd_stage2_target(generic_stage_target):
+	"""
+	Builder class for a LiveCD stage2 build.
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=["boot/kernel"]
+
+		self.valid_values=[]
+
+		self.valid_values.extend(self.required_values)
+		self.valid_values.extend(["livecd/cdtar","livecd/empty","livecd/rm",\
+			"livecd/unmerge","livecd/iso","livecd/gk_mainargs","livecd/type",\
+			"livecd/readme","livecd/motd","livecd/overlay",\
+			"livecd/modblacklist","livecd/splash_theme","livecd/rcadd",\
+			"livecd/rcdel","livecd/fsscript","livecd/xinitrc",\
+			"livecd/root_overlay","livecd/users","portage_overlay",\
+			"livecd/fstype","livecd/fsops","livecd/linuxrc","livecd/bootargs",\
+			"gamecd/conf","livecd/xdm","livecd/xsession","livecd/volid"])
+
+		generic_stage_target.__init__(self,spec,addlargs)
+		if "livecd/type" not in self.settings:
+			self.settings["livecd/type"] = "generic-livecd"
+
+		file_locate(self.settings, ["cdtar","controller_file"])
+
+	def set_source_path(self):
+		self.settings["source_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2")
+		if os.path.isfile(self.settings["source_path"]):
+			self.settings["source_path_hash"]=generate_hash(self.settings["source_path"])
+		else:
+			self.settings["source_path"]=normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/")
+		if not os.path.exists(self.settings["source_path"]):
+			raise CatalystError,"Source Path: "+self.settings["source_path"]+" does not exist."
+
+	def set_spec_prefix(self):
+	    self.settings["spec_prefix"]="livecd"
+
+	def set_target_path(self):
+		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["target_subpath"]+"/")
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
+				print "Resume point detected, skipping target path setup operation..."
+		else:
+			# first clean up any existing target stuff
+			if os.path.isdir(self.settings["target_path"]):
+				cmd("rm -rf "+self.settings["target_path"],
+				"Could not remove existing directory: "+self.settings["target_path"],env=self.env)
+				touch(self.settings["autoresume_path"]+"setup_target_path")
+			if not os.path.exists(self.settings["target_path"]):
+				os.makedirs(self.settings["target_path"])
+
+	def run_local(self):
+		# what modules do we want to blacklist?
+		if "livecd/modblacklist" in self.settings:
+			try:
+				myf=open(self.settings["chroot_path"]+"/etc/modprobe.d/blacklist.conf","a")
+			except:
+				self.unbind()
+				raise CatalystError,"Couldn't open "+self.settings["chroot_path"]+"/etc/modprobe.d/blacklist.conf."
+
+			myf.write("\n#Added by Catalyst:")
+			# workaround until config.py is using configparser
+			if isinstance(self.settings["livecd/modblacklist"], str):
+				self.settings["livecd/modblacklist"] = self.settings["livecd/modblacklist"].split()
+			for x in self.settings["livecd/modblacklist"]:
+				myf.write("\nblacklist "+x)
+			myf.close()
+
+	def unpack(self):
+		unpack=True
+		display_msg=None
+
+		clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+"unpack")
+
+		if os.path.isdir(self.settings["source_path"]):
+			unpack_cmd="rsync -a --delete "+self.settings["source_path"]+" "+self.settings["chroot_path"]
+			display_msg="\nStarting rsync from "+self.settings["source_path"]+"\nto "+\
+				self.settings["chroot_path"]+" (This may take some time) ...\n"
+			error_msg="Rsync of "+self.settings["source_path"]+" to "+self.settings["chroot_path"]+" failed."
+			invalid_snapshot=False
+
+		if "AUTORESUME" in self.settings:
+			if os.path.isdir(self.settings["source_path"]) and \
+				os.path.exists(self.settings["autoresume_path"]+"unpack"):
+				print "Resume point detected, skipping unpack operation..."
+				unpack=False
+			elif "source_path_hash" in self.settings:
+				if self.settings["source_path_hash"] != clst_unpack_hash:
+					invalid_snapshot=True
+
+		if unpack:
+			self.mount_safety_check()
+			if invalid_snapshot:
+				print "No Valid Resume point detected, cleaning up  ..."
+				#os.remove(self.settings["autoresume_path"]+"dir_setup")
+				self.clear_autoresume()
+				self.clear_chroot()
+				#self.dir_setup()
+
+			if not os.path.exists(self.settings["chroot_path"]):
+				os.makedirs(self.settings["chroot_path"])
+
+			if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
+				os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
+
+			if "PKGCACHE" in self.settings:
+				if not os.path.exists(self.settings["pkgcache_path"]):
+					os.makedirs(self.settings["pkgcache_path"],0755)
+
+			if not display_msg:
+				raise CatalystError,"Could not find appropriate source. Please check the 'source_subpath' setting in the spec file."
+
+			print display_msg
+			cmd(unpack_cmd,error_msg,env=self.env)
+
+			if "source_path_hash" in self.settings:
+				myf=open(self.settings["autoresume_path"]+"unpack","w")
+				myf.write(self.settings["source_path_hash"])
+				myf.close()
+			else:
+				touch(self.settings["autoresume_path"]+"unpack")
+
+	def set_action_sequence(self):
+		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
+				"config_profile_link","setup_confdir","portage_overlay",\
+				"bind","chroot_setup","setup_environment","run_local",\
+				"build_kernel"]
+		if "FETCH" not in self.settings:
+			self.settings["action_sequence"] += ["bootloader","preclean",\
+				"livecd_update","root_overlay","fsscript","rcupdate","unmerge",\
+				"unbind","remove","empty","target_setup",\
+				"setup_overlay","create_iso"]
+		self.settings["action_sequence"].append("clear_autoresume")
+
+def register(foo):
+	foo.update({"livecd-stage2":livecd_stage2_target})
+	return foo
diff --git a/catalyst/targets/netboot2_target.py b/catalyst/targets/netboot2_target.py
new file mode 100644
index 0000000..2b3cd20
--- /dev/null
+++ b/catalyst/targets/netboot2_target.py
@@ -0,0 +1,166 @@
+"""
+netboot target, version 2
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+import os,string,types
+from catalyst.support import *
+from generic_stage_target import *
+
+class netboot2_target(generic_stage_target):
+	"""
+	Builder class for a netboot build, version 2
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=[
+			"boot/kernel"
+		]
+		self.valid_values=self.required_values[:]
+		self.valid_values.extend([
+			"netboot2/packages",
+			"netboot2/use",
+			"netboot2/extra_files",
+			"netboot2/overlay",
+			"netboot2/busybox_config",
+			"netboot2/root_overlay",
+			"netboot2/linuxrc"
+		])
+
+		try:
+			if "netboot2/packages" in addlargs:
+				if type(addlargs["netboot2/packages"]) == types.StringType:
+					loopy=[addlargs["netboot2/packages"]]
+				else:
+					loopy=addlargs["netboot2/packages"]
+
+				for x in loopy:
+					self.valid_values.append("netboot2/packages/"+x+"/files")
+		except:
+			raise CatalystError,"configuration error in netboot2/packages."
+
+		generic_stage_target.__init__(self,spec,addlargs)
+		self.set_build_kernel_vars()
+		self.settings["merge_path"]=normpath("/tmp/image/")
+
+	def set_target_path(self):
+		self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+\
+			self.settings["target_subpath"]+"/")
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
+				print "Resume point detected, skipping target path setup operation..."
+		else:
+			# first clean up any existing target stuff
+			if os.path.isfile(self.settings["target_path"]):
+				cmd("rm -f "+self.settings["target_path"], \
+					"Could not remove existing file: "+self.settings["target_path"],env=self.env)
+				touch(self.settings["autoresume_path"]+"setup_target_path")
+
+		if not os.path.exists(self.settings["storedir"]+"/builds/"):
+			os.makedirs(self.settings["storedir"]+"/builds/")
+
+	def copy_files_to_image(self):
+		# copies specific files from the buildroot to merge_path
+		myfiles=[]
+
+		# check for autoresume point
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"copy_files_to_image"):
+				print "Resume point detected, skipping target path setup operation..."
+		else:
+			if "netboot2/packages" in self.settings:
+				if type(self.settings["netboot2/packages"]) == types.StringType:
+					loopy=[self.settings["netboot2/packages"]]
+				else:
+					loopy=self.settings["netboot2/packages"]
+
+			for x in loopy:
+				if "netboot2/packages/"+x+"/files" in self.settings:
+				    if type(self.settings["netboot2/packages/"+x+"/files"]) == types.ListType:
+					    myfiles.extend(self.settings["netboot2/packages/"+x+"/files"])
+				    else:
+					    myfiles.append(self.settings["netboot2/packages/"+x+"/files"])
+
+			if "netboot2/extra_files" in self.settings:
+				if type(self.settings["netboot2/extra_files"]) == types.ListType:
+					myfiles.extend(self.settings["netboot2/extra_files"])
+				else:
+					myfiles.append(self.settings["netboot2/extra_files"])
+
+			try:
+				cmd("/bin/bash "+self.settings["controller_file"]+\
+					" image " + list_bashify(myfiles),env=self.env)
+			except CatalystError:
+				self.unbind()
+				raise CatalystError,"Failed to copy files to image!"
+
+			touch(self.settings["autoresume_path"]+"copy_files_to_image")
+
+	def setup_overlay(self):
+		if "AUTORESUME" in self.settings \
+		and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
+			print "Resume point detected, skipping setup_overlay operation..."
+		else:
+			if "netboot2/overlay" in self.settings:
+				for x in self.settings["netboot2/overlay"]:
+					if os.path.exists(x):
+						cmd("rsync -a "+x+"/ "+\
+							self.settings["chroot_path"] + self.settings["merge_path"], "netboot2/overlay: "+x+" copy failed.",env=self.env)
+				touch(self.settings["autoresume_path"]+"setup_overlay")
+
+	def move_kernels(self):
+		# we're done, move the kernels to builds/*
+		# no auto resume here as we always want the
+		# freshest images moved
+		try:
+			cmd("/bin/bash "+self.settings["controller_file"]+\
+				" final",env=self.env)
+			print ">>> Netboot Build Finished!"
+		except CatalystError:
+			self.unbind()
+			raise CatalystError,"Failed to move kernel images!"
+
+	def remove(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"remove"):
+			print "Resume point detected, skipping remove operation..."
+		else:
+			if self.settings["spec_prefix"]+"/rm" in self.settings:
+				for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
+					# we're going to shell out for all these cleaning operations,
+					# so we get easy glob handling
+					print "netboot2: removing " + x
+					os.system("rm -rf " + self.settings["chroot_path"] + self.settings["merge_path"] + x)
+
+	def empty(self):
+		if "AUTORESUME" in self.settings \
+			and os.path.exists(self.settings["autoresume_path"]+"empty"):
+			print "Resume point detected, skipping empty operation..."
+		else:
+			if "netboot2/empty" in self.settings:
+				if type(self.settings["netboot2/empty"])==types.StringType:
+					self.settings["netboot2/empty"]=self.settings["netboot2/empty"].split()
+				for x in self.settings["netboot2/empty"]:
+					myemp=self.settings["chroot_path"] + self.settings["merge_path"] + x
+					if not os.path.isdir(myemp):
+						print x,"not a directory or does not exist, skipping 'empty' operation."
+						continue
+					print "Emptying directory", x
+					# stat the dir, delete the dir, recreate the dir and set
+					# the proper perms and ownership
+					mystat=os.stat(myemp)
+					shutil.rmtree(myemp)
+					os.makedirs(myemp,0755)
+					os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
+					os.chmod(myemp,mystat[ST_MODE])
+		touch(self.settings["autoresume_path"]+"empty")
+
+	def set_action_sequence(self):
+	    self.settings["action_sequence"]=["unpack","unpack_snapshot","config_profile_link",
+	    				"setup_confdir","portage_overlay","bind","chroot_setup",\
+					"setup_environment","build_packages","root_overlay",\
+					"copy_files_to_image","setup_overlay","build_kernel","move_kernels",\
+					"remove","empty","unbind","clean","clear_autoresume"]
+
+def register(foo):
+	foo.update({"netboot2":netboot2_target})
+	return foo
diff --git a/catalyst/targets/netboot_target.py b/catalyst/targets/netboot_target.py
new file mode 100644
index 0000000..9d01b7e
--- /dev/null
+++ b/catalyst/targets/netboot_target.py
@@ -0,0 +1,128 @@
+"""
+netboot target, version 1
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+import os,string,types
+from catalyst.support import *
+from generic_stage_target import *
+
+class netboot_target(generic_stage_target):
+	"""
+	Builder class for a netboot build.
+	"""
+	def __init__(self,spec,addlargs):
+		self.valid_values = [
+			"netboot/kernel/sources",
+			"netboot/kernel/config",
+			"netboot/kernel/prebuilt",
+
+			"netboot/busybox_config",
+
+			"netboot/extra_files",
+			"netboot/packages"
+		]
+		self.required_values=[]
+
+		try:
+			if "netboot/packages" in addlargs:
+				if type(addlargs["netboot/packages"]) == types.StringType:
+					loopy=[addlargs["netboot/packages"]]
+				else:
+					loopy=addlargs["netboot/packages"]
+
+		#	for x in loopy:
+		#		self.required_values.append("netboot/packages/"+x+"/files")
+		except:
+			raise CatalystError,"configuration error in netboot/packages."
+
+		generic_stage_target.__init__(self,spec,addlargs)
+		self.set_build_kernel_vars(addlargs)
+		if "netboot/busybox_config" in addlargs:
+			file_locate(self.settings, ["netboot/busybox_config"])
+
+		# Custom Kernel Tarball --- use that instead ...
+
+		# unless the user wants specific CFLAGS/CXXFLAGS, let's use -Os
+
+		for envvar in "CFLAGS", "CXXFLAGS":
+			if envvar not in os.environ and envvar not in addlargs:
+				self.settings[envvar] = "-Os -pipe"
+
+	def set_root_path(self):
+		# ROOT= variable for emerges
+		self.settings["root_path"]=normpath("/tmp/image")
+		print "netboot root path is "+self.settings["root_path"]
+
+#	def build_packages(self):
+#		# build packages
+#		if "netboot/packages" in self.settings:
+#			mypack=list_bashify(self.settings["netboot/packages"])
+#		try:
+#			cmd("/bin/bash "+self.settings["controller_file"]+" packages "+mypack,env=self.env)
+#		except CatalystError:
+#			self.unbind()
+#			raise CatalystError,"netboot build aborting due to error."
+
+	def build_busybox(self):
+		# build busybox
+		if "netboot/busybox_config" in self.settings:
+			mycmd = self.settings["netboot/busybox_config"]
+		else:
+			mycmd = ""
+		try:
+			cmd("/bin/bash "+self.settings["controller_file"]+" busybox "+ mycmd,env=self.env)
+		except CatalystError:
+			self.unbind()
+			raise CatalystError,"netboot build aborting due to error."
+
+	def copy_files_to_image(self):
+		# create image
+		myfiles=[]
+		if "netboot/packages" in self.settings:
+			if type(self.settings["netboot/packages"]) == types.StringType:
+				loopy=[self.settings["netboot/packages"]]
+			else:
+				loopy=self.settings["netboot/packages"]
+
+		for x in loopy:
+			if "netboot/packages/"+x+"/files" in self.settings:
+			    if type(self.settings["netboot/packages/"+x+"/files"]) == types.ListType:
+				    myfiles.extend(self.settings["netboot/packages/"+x+"/files"])
+			    else:
+				    myfiles.append(self.settings["netboot/packages/"+x+"/files"])
+
+		if "netboot/extra_files" in self.settings:
+			if type(self.settings["netboot/extra_files"]) == types.ListType:
+				myfiles.extend(self.settings["netboot/extra_files"])
+			else:
+				myfiles.append(self.settings["netboot/extra_files"])
+
+		try:
+			cmd("/bin/bash "+self.settings["controller_file"]+\
+				" image " + list_bashify(myfiles),env=self.env)
+		except CatalystError:
+			self.unbind()
+			raise CatalystError,"netboot build aborting due to error."
+
+	def create_netboot_files(self):
+		# finish it all up
+		try:
+			cmd("/bin/bash "+self.settings["controller_file"]+" finish",env=self.env)
+		except CatalystError:
+			self.unbind()
+			raise CatalystError,"netboot build aborting due to error."
+
+		# end
+		print "netboot: build finished !"
+
+	def set_action_sequence(self):
+	    self.settings["action_sequence"]=["unpack","unpack_snapshot",
+	    				"config_profile_link","setup_confdir","bind","chroot_setup",\
+						"setup_environment","build_packages","build_busybox",\
+						"build_kernel","copy_files_to_image",\
+						"clean","create_netboot_files","unbind","clear_autoresume"]
+
+def register(foo):
+	foo.update({"netboot":netboot_target})
+	return foo
diff --git a/catalyst/targets/snapshot_target.py b/catalyst/targets/snapshot_target.py
new file mode 100644
index 0000000..e21bd1a
--- /dev/null
+++ b/catalyst/targets/snapshot_target.py
@@ -0,0 +1,91 @@
+"""
+Snapshot target
+"""
+
+import os
+from catalyst.support import *
+from generic_stage_target import *
+
+class snapshot_target(generic_stage_target):
+	"""
+	Builder class for snapshots.
+	"""
+	def __init__(self,myspec,addlargs):
+		self.required_values=["version_stamp","target"]
+		self.valid_values=["version_stamp","target"]
+
+		generic_target.__init__(self,myspec,addlargs)
+		self.settings=myspec
+		self.settings["target_subpath"]="portage"
+		st=self.settings["storedir"]
+		self.settings["snapshot_path"]=normpath(st + "/snapshots/"
+			+ self.settings["snapshot_name"]
+			+ self.settings["version_stamp"] + ".tar.bz2")
+		self.settings["tmp_path"]=normpath(st+"/tmp/"+self.settings["target_subpath"])
+
+	def setup(self):
+		x=normpath(self.settings["storedir"]+"/snapshots")
+		if not os.path.exists(x):
+			os.makedirs(x)
+
+	def mount_safety_check(self):
+		pass
+
+	def run(self):
+		if "PURGEONLY" in self.settings:
+			self.purge()
+			return
+
+		if "PURGE" in self.settings:
+			self.purge()
+
+		self.setup()
+		print "Creating Portage tree snapshot "+self.settings["version_stamp"]+\
+			" from "+self.settings["portdir"]+"..."
+
+		mytmp=self.settings["tmp_path"]
+		if not os.path.exists(mytmp):
+			os.makedirs(mytmp)
+
+		cmd("rsync -a --delete --exclude /packages/ --exclude /distfiles/ " +
+			"--exclude /local/ --exclude CVS/ --exclude .svn --filter=H_**/files/digest-* " +
+			self.settings["portdir"] + "/ " + mytmp + "/%s/" % self.settings["repo_name"],
+			"Snapshot failure",env=self.env)
+
+		print "Compressing Portage snapshot tarball..."
+		cmd("tar -I lbzip2 -cf " + self.settings["snapshot_path"] + " -C " +
+			mytmp + " %s" % self.settings["repo_name"],
+			"Snapshot creation failure",env=self.env)
+
+		self.gen_contents_file(self.settings["snapshot_path"])
+		self.gen_digest_file(self.settings["snapshot_path"])
+
+		self.cleanup()
+		print "snapshot: complete!"
+
+	def kill_chroot_pids(self):
+		pass
+
+	def cleanup(self):
+		print "Cleaning up..."
+
+	def purge(self):
+		myemp=self.settings["tmp_path"]
+		if os.path.isdir(myemp):
+			print "Emptying directory",myemp
+			"""
+			stat the dir, delete the dir, recreate the dir and set
+			the proper perms and ownership
+			"""
+			mystat=os.stat(myemp)
+			""" There's no easy way to change flags recursively in python """
+			if os.uname()[0] == "FreeBSD":
+				os.system("chflags -R noschg "+myemp)
+			shutil.rmtree(myemp)
+			os.makedirs(myemp,0755)
+			os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
+			os.chmod(myemp,mystat[ST_MODE])
+
+def register(foo):
+	foo.update({"snapshot":snapshot_target})
+	return foo
diff --git a/catalyst/targets/stage1_target.py b/catalyst/targets/stage1_target.py
new file mode 100644
index 0000000..25f7116
--- /dev/null
+++ b/catalyst/targets/stage1_target.py
@@ -0,0 +1,96 @@
+"""
+stage1 target
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+from catalyst.support import *
+from generic_stage_target import *
+
+class stage1_target(generic_stage_target):
+	"""
+	Builder class for a stage1 installation tarball build.
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=[]
+		self.valid_values=["chost"]
+		self.valid_values.extend(["update_seed","update_seed_command"])
+		generic_stage_target.__init__(self,spec,addlargs)
+
+	def set_stage_path(self):
+		self.settings["stage_path"]=normpath(self.settings["chroot_path"]+self.settings["root_path"])
+		print "stage1 stage path is "+self.settings["stage_path"]
+
+	def set_root_path(self):
+		# sets the root path, relative to 'chroot_path', of the stage1 root
+		self.settings["root_path"]=normpath("/tmp/stage1root")
+		print "stage1 root path is "+self.settings["root_path"]
+
+	def set_cleanables(self):
+		generic_stage_target.set_cleanables(self)
+		self.settings["cleanables"].extend([\
+		"/usr/share/zoneinfo", "/etc/portage/package*"])
+
+	# XXX: How do these override_foo() functions differ from the ones in generic_stage_target and why aren't they in stage3_target?
+
+	def override_chost(self):
+		if "chost" in self.settings:
+			self.settings["CHOST"]=list_to_string(self.settings["chost"])
+
+	def override_cflags(self):
+		if "cflags" in self.settings:
+			self.settings["CFLAGS"]=list_to_string(self.settings["cflags"])
+
+	def override_cxxflags(self):
+		if "cxxflags" in self.settings:
+			self.settings["CXXFLAGS"]=list_to_string(self.settings["cxxflags"])
+
+	def override_ldflags(self):
+		if "ldflags" in self.settings:
+			self.settings["LDFLAGS"]=list_to_string(self.settings["ldflags"])
+
+	def set_portage_overlay(self):
+		generic_stage_target.set_portage_overlay(self)
+		if "portage_overlay" in self.settings:
+			print "\nWARNING !!!!!"
+			print "\tUsing an portage overlay for earlier stages could cause build issues."
+			print "\tIf you break it, you buy it. Don't complain to us about it."
+			print "\tDont say we did not warn you\n"
+
+	def base_dirs(self):
+		if os.uname()[0] == "FreeBSD":
+			# baselayout no longer creates the .keep files in proc and dev for FreeBSD as it
+			# would create them too late...we need them earlier before bind mounting filesystems
+			# since proc and dev are not writeable, so...create them here
+			if not os.path.exists(self.settings["stage_path"]+"/proc"):
+				os.makedirs(self.settings["stage_path"]+"/proc")
+			if not os.path.exists(self.settings["stage_path"]+"/dev"):
+				os.makedirs(self.settings["stage_path"]+"/dev")
+			if not os.path.isfile(self.settings["stage_path"]+"/proc/.keep"):
+				try:
+					proc_keepfile = open(self.settings["stage_path"]+"/proc/.keep","w")
+					proc_keepfile.write('')
+					proc_keepfile.close()
+				except IOError:
+					print "!!! Failed to create %s" % (self.settings["stage_path"]+"/dev/.keep")
+			if not os.path.isfile(self.settings["stage_path"]+"/dev/.keep"):
+				try:
+					dev_keepfile = open(self.settings["stage_path"]+"/dev/.keep","w")
+					dev_keepfile.write('')
+					dev_keepfile.close()
+				except IOError:
+					print "!!! Failed to create %s" % (self.settings["stage_path"]+"/dev/.keep")
+		else:
+			pass
+
+	def set_mounts(self):
+		# stage_path/proc probably doesn't exist yet, so create it
+		if not os.path.exists(self.settings["stage_path"]+"/proc"):
+			os.makedirs(self.settings["stage_path"]+"/proc")
+
+		# alter the mount mappings to bind mount proc onto it
+		self.mounts.append("/tmp/stage1root/proc")
+		self.mountmap["/tmp/stage1root/proc"]="/proc"
+
+def register(foo):
+	foo.update({"stage1":stage1_target})
+	return foo
diff --git a/catalyst/targets/stage2_target.py b/catalyst/targets/stage2_target.py
new file mode 100644
index 0000000..15acdee
--- /dev/null
+++ b/catalyst/targets/stage2_target.py
@@ -0,0 +1,62 @@
+"""
+stage2 target, builds upon previous stage1 tarball
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+from catalyst.support import *
+from generic_stage_target import *
+
+class stage2_target(generic_stage_target):
+	"""
+	Builder class for a stage2 installation tarball build.
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=[]
+		self.valid_values=["chost"]
+		generic_stage_target.__init__(self,spec,addlargs)
+
+	def set_source_path(self):
+		if "SEEDCACHE" in self.settings and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/tmp/stage1root/")):
+			self.settings["source_path"]=normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/tmp/stage1root/")
+		else:
+			self.settings["source_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2")
+			if os.path.isfile(self.settings["source_path"]):
+				if os.path.exists(self.settings["source_path"]):
+				# XXX: Is this even necessary if the previous check passes?
+					self.settings["source_path_hash"]=generate_hash(self.settings["source_path"],\
+						hash_function=self.settings["hash_function"],verbose=False)
+		print "Source path set to "+self.settings["source_path"]
+		if os.path.isdir(self.settings["source_path"]):
+			print "\tIf this is not desired, remove this directory or turn of seedcache in the options of catalyst.conf"
+			print "\tthe source path will then be "+normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2\n")
+
+	# XXX: How do these override_foo() functions differ from the ones in
+	# generic_stage_target and why aren't they in stage3_target?
+
+	def override_chost(self):
+		if "chost" in self.settings:
+			self.settings["CHOST"]=list_to_string(self.settings["chost"])
+
+	def override_cflags(self):
+		if "cflags" in self.settings:
+			self.settings["CFLAGS"]=list_to_string(self.settings["cflags"])
+
+	def override_cxxflags(self):
+		if "cxxflags" in self.settings:
+			self.settings["CXXFLAGS"]=list_to_string(self.settings["cxxflags"])
+
+	def override_ldflags(self):
+		if "ldflags" in self.settings:
+			self.settings["LDFLAGS"]=list_to_string(self.settings["ldflags"])
+
+	def set_portage_overlay(self):
+			generic_stage_target.set_portage_overlay(self)
+			if "portage_overlay" in self.settings:
+				print "\nWARNING !!!!!"
+				print "\tUsing an portage overlay for earlier stages could cause build issues."
+				print "\tIf you break it, you buy it. Don't complain to us about it."
+				print "\tDont say we did not warn you\n"
+
+def register(foo):
+	foo.update({"stage2":stage2_target})
+	return foo
diff --git a/catalyst/targets/stage3_target.py b/catalyst/targets/stage3_target.py
new file mode 100644
index 0000000..89edd66
--- /dev/null
+++ b/catalyst/targets/stage3_target.py
@@ -0,0 +1,31 @@
+"""
+stage3 target, builds upon previous stage2/stage3 tarball
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+from catalyst.support import *
+from generic_stage_target import *
+
+class stage3_target(generic_stage_target):
+	"""
+	Builder class for a stage3 installation tarball build.
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=[]
+		self.valid_values=[]
+		generic_stage_target.__init__(self,spec,addlargs)
+
+	def set_portage_overlay(self):
+		generic_stage_target.set_portage_overlay(self)
+		if "portage_overlay" in self.settings:
+			print "\nWARNING !!!!!"
+			print "\tUsing an overlay for earlier stages could cause build issues."
+			print "\tIf you break it, you buy it. Don't complain to us about it."
+			print "\tDont say we did not warn you\n"
+
+	def set_cleanables(self):
+		generic_stage_target.set_cleanables(self)
+
+def register(foo):
+	foo.update({"stage3":stage3_target})
+	return foo
diff --git a/catalyst/targets/stage4_target.py b/catalyst/targets/stage4_target.py
new file mode 100644
index 0000000..9168f2e
--- /dev/null
+++ b/catalyst/targets/stage4_target.py
@@ -0,0 +1,43 @@
+"""
+stage4 target, builds upon previous stage3/stage4 tarball
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+from catalyst.support import *
+from generic_stage_target import *
+
+class stage4_target(generic_stage_target):
+	"""
+	Builder class for stage4.
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=["stage4/packages"]
+		self.valid_values=self.required_values[:]
+		self.valid_values.extend(["stage4/use","boot/kernel",\
+				"stage4/root_overlay","stage4/fsscript",\
+				"stage4/gk_mainargs","splash_theme",\
+				"portage_overlay","stage4/rcadd","stage4/rcdel",\
+				"stage4/linuxrc","stage4/unmerge","stage4/rm","stage4/empty"])
+		generic_stage_target.__init__(self,spec,addlargs)
+
+	def set_cleanables(self):
+		self.settings["cleanables"]=["/var/tmp/*","/tmp/*"]
+
+	def set_action_sequence(self):
+		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
+					"config_profile_link","setup_confdir","portage_overlay",\
+					"bind","chroot_setup","setup_environment","build_packages",\
+					"build_kernel","bootloader","root_overlay","fsscript",\
+					"preclean","rcupdate","unmerge","unbind","remove","empty",\
+					"clean"]
+
+#		if "TARBALL" in self.settings or \
+#			"FETCH" not in self.settings:
+		if "FETCH" not in self.settings:
+			self.settings["action_sequence"].append("capture")
+		self.settings["action_sequence"].append("clear_autoresume")
+
+def register(foo):
+	foo.update({"stage4":stage4_target})
+	return foo
+
diff --git a/catalyst/targets/tinderbox_target.py b/catalyst/targets/tinderbox_target.py
new file mode 100644
index 0000000..5985c5b
--- /dev/null
+++ b/catalyst/targets/tinderbox_target.py
@@ -0,0 +1,44 @@
+"""
+Tinderbox target
+"""
+# NOTE: That^^ docstring has influence catalyst-spec(5) man page generation.
+
+from catalyst.support import *
+from generic_stage_target import *
+
+class tinderbox_target(generic_stage_target):
+	"""
+	Builder class for the tinderbox target
+	"""
+	def __init__(self,spec,addlargs):
+		self.required_values=["tinderbox/packages"]
+		self.valid_values=self.required_values[:]
+		self.valid_values.extend(["tinderbox/use"])
+		generic_stage_target.__init__(self,spec,addlargs)
+
+	def run_local(self):
+		# tinderbox
+		# example call: "grp.sh run xmms vim sys-apps/gleep"
+		try:
+			if os.path.exists(self.settings["controller_file"]):
+			    cmd("/bin/bash "+self.settings["controller_file"]+" run "+\
+				list_bashify(self.settings["tinderbox/packages"]),"run script failed.",env=self.env)
+
+		except CatalystError:
+			self.unbind()
+			raise CatalystError,"Tinderbox aborting due to error."
+
+	def set_cleanables(self):
+	    self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/root/*",
+					self.settings['portdir']]
+
+	def set_action_sequence(self):
+		#Default action sequence for run method
+		self.settings["action_sequence"]=["unpack","unpack_snapshot",\
+		              "config_profile_link","setup_confdir","bind","chroot_setup",\
+		              "setup_environment","run_local","preclean","unbind","clean",\
+		              "clear_autoresume"]
+
+def register(foo):
+	foo.update({"tinderbox":tinderbox_target})
+	return foo
-- 
1.8.3.2



  parent reply	other threads:[~2013-12-14  3:21 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-14  3:20 [gentoo-catalyst] rewrite-on-master patches, round-2 Brian Dolbec
2013-12-14  3:20 ` [gentoo-catalyst] [PATCH 1/4] Initial rearrangement of the python directories Brian Dolbec
2013-12-14  5:22   ` Matt Turner
2013-12-14  5:48     ` W. Trevor King
2013-12-14 12:12     ` Brian Dolbec
2013-12-14 14:17   ` Dylan Baker
2013-12-14 16:42     ` Brian Dolbec
2013-12-14 23:57     ` W. Trevor King
2013-12-14  3:20 ` [gentoo-catalyst] [PATCH 2/4] move catalyst_support, builder, catalyst_lock out of modules, into the catalyst's base namespace Brian Dolbec
2013-12-14  3:20 ` Brian Dolbec [this message]
2013-12-14  3:20 ` [gentoo-catalyst] [PATCH 4/4] rename files directory to etc to better reflect the directories contents Brian Dolbec
2013-12-15  4:39   ` W. Trevor King

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1386991211-9296-4-git-send-email-dolsen@gentoo.org \
    --to=dolsen@gentoo.org \
    --cc=gentoo-catalyst@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox