Move export of FEATURES to setup_myfeatures.
[catalyst.git] / modules / generic_stage_target.py
1
2 """
3 This class does all of the chroot setup, copying of files, etc. It is
4 the driver class for pretty much everything that Catalyst does.
5 """
6
7 import os,string,imp,types,shutil
8 from catalyst_support import *
9 from generic_target import *
10 from stat import *
11 import catalyst_lock
12 class generic_stage_target(generic_target):
13
14         def __init__(self,myspec,addlargs):
15                 self.required_values.extend(["version_stamp","target","subarch",\
16                         "rel_type","profile","snapshot","source_subpath"])
17                 
18                 self.valid_values.extend(["version_stamp","target","subarch",\
19                         "rel_type","profile","snapshot","source_subpath","portage_confdir",\
20                         "cflags","cxxflags","ldflags","cbuild","hostuse","portage_overlay",\
21                         "distcc_hosts","makeopts","pkgcache_path","kerncache_path"])
22                 
23                 self.set_valid_build_kernel_vars(addlargs)
24                 generic_target.__init__(self,myspec,addlargs)
25
26                 # The semantics of subarchmap and machinemap changed a bit in 2.0.3 to
27                 # work better with vapier's CBUILD stuff. I've removed the "monolithic"
28                 # machinemap from this file and split up its contents amongst the
29                 # various arch/foo.py files.
30                 #
31                 # When register() is called on each module in the arch/ dir, it now
32                 # returns a tuple instead of acting on the subarchmap dict that is
33                 # passed to it. The tuple contains the values that were previously
34                 # added to subarchmap as well as a new list of CHOSTs that go along
35                 # with that arch. This allows us to build machinemap on the fly based
36                 # on the keys in subarchmap and the values of the 2nd list returned
37                 # (tmpmachinemap).
38                 #
39                 # Also, after talking with vapier. I have a slightly better idea of what
40                 # certain variables are used for and what they should be set to. Neither
41                 # 'buildarch' or 'hostarch' are used directly, so their value doesn't
42                 # really matter. They are just compared to determine if we are
43                 # cross-compiling. Because of this, they are just set to the name of the
44                 # module in arch/ that the subarch is part of to make things simpler.
45                 # The entire build process is still based off of 'subarch' like it was
46                 # previously. -agaffney
47
48                 self.archmap = {}
49                 self.subarchmap = {}
50                 machinemap = {}
51                 for x in [x[:-3] for x in os.listdir(self.settings["sharedir"]+"/arch/") if x.endswith(".py")]:
52                         try:
53                                 fh=open(self.settings["sharedir"]+"/arch/"+x+".py")
54                                 # This next line loads the plugin as a module and assigns it to
55                                 # archmap[x]
56                                 self.archmap[x]=imp.load_module(x,fh,"arch/"+x+".py",(".py","r",imp.PY_SOURCE))
57                                 # This next line registers all the subarches supported in the
58                                 # plugin
59                                 tmpsubarchmap, tmpmachinemap = self.archmap[x].register()
60                                 self.subarchmap.update(tmpsubarchmap)
61                                 for machine in tmpmachinemap:
62                                         machinemap[machine] = x
63                                 for subarch in tmpsubarchmap:
64                                         machinemap[subarch] = x
65                                 fh.close()      
66                         except IOError:
67                                 # This message should probably change a bit, since everything in the dir should
68                                 # load just fine. If it doesn't, it's probably a syntax error in the module
69                                 msg("Can't find "+x+".py plugin in "+self.settings["sharedir"]+"/arch/")
70
71                 if self.settings.has_key("chost"):
72                         hostmachine = self.settings["chost"].split("-")[0]
73                         if not machinemap.has_key(hostmachine):
74                                 raise CatalystError, "Unknown host machine type "+hostmachine
75                         self.settings["hostarch"] = machinemap[hostmachine]
76                 else:
77                         hostmachine = self.settings["subarch"]
78                         if machinemap.has_key(hostmachine):
79                                 hostmachine = machinemap[hostmachine]
80                         self.settings["hostarch"] = hostmachine
81                 if self.settings.has_key("cbuild"):
82                         buildmachine = self.settings["cbuild"].split("-")[0]
83                 else:
84                         buildmachine = os.uname()[4]
85                 if not machinemap.has_key(buildmachine):
86                         raise CatalystError, "Unknown build machine type "+buildmachine
87                 self.settings["buildarch"] = machinemap[buildmachine]
88                 self.settings["crosscompile"] = (self.settings["hostarch"] != self.settings["buildarch"])
89                 
90                 # Call arch constructor, pass our settings
91                 try:
92                         self.arch=self.subarchmap[self.settings["subarch"]](self.settings)
93                 except KeyError:
94                         print "Invalid subarch: "+self.settings["subarch"]
95                         print "Choose one of the following:",
96                         for x in self.subarchmap:
97                                 print x,
98                         print
99                         sys.exit(2)
100
101                 print "Using target:",self.settings["target"]
102                 # print a nice informational message:
103                 if self.settings["buildarch"]==self.settings["hostarch"]:
104                         print "Building natively for",self.settings["hostarch"]
105                 elif self.settings["crosscompile"]:
106                         print "Cross-compiling on",self.settings["buildarch"],"for different machine type",\
107                                 self.settings["hostarch"]
108                 else:
109                         print "Building on",self.settings["buildarch"],"for alternate personality type",\
110                                 self.settings["hostarch"]
111
112                 # This should be first to be set as other set_ options depend on this
113                 self.set_spec_prefix()
114                 
115                 # define all of our core variables
116                 self.set_target_profile()
117                 self.set_target_subpath()
118                 self.set_source_subpath()
119
120                 # set paths
121                 self.set_snapshot_path()
122                 self.set_root_path()
123                 self.set_source_path()
124                 self.set_snapcache_path()
125                 self.set_chroot_path()
126                 self.set_autoresume_path()
127                 self.set_dest_path()
128                 self.set_stage_path()
129                 self.set_target_path()
130                 
131                 self.set_controller_file()
132                 self.set_action_sequence()
133                 self.set_use()
134                 self.set_cleanables()
135                 self.set_iso_volume_id()
136                 self.set_build_kernel_vars()
137                 self.set_fsscript()
138                 self.set_archscript()
139                 self.set_runscript()
140                 self.set_install_mask()
141                 self.set_rcadd()
142                 self.set_rcdel()
143                 self.set_cdtar()
144                 self.set_fstype()
145                 self.set_fsops()
146                 self.set_iso()
147                 self.set_packages()
148                 self.set_rm()
149                 self.set_linuxrc()
150                 self.set_overlay()      
151                 self.set_portage_overlay()      
152                 self.set_root_overlay() 
153                 
154                 # This next line checks to make sure that the specified variables exist
155                 # on disk.
156                 #pdb.set_trace()
157                 file_locate(self.settings,["source_path","snapshot_path","distdir"],expand=0)
158                 # If we are using portage_confdir, check that as well.
159                 if self.settings.has_key("portage_confdir"):
160                         file_locate(self.settings,["portage_confdir"],expand=0)
161                 
162                 # setup our mount points
163                 if self.settings.has_key("SNAPCACHE"):
164                         self.mounts=[ "/proc","/dev","/usr/portage","/usr/portage/distfiles" ]
165                         self.mountmap={"/proc":"/proc", "/dev":"/dev", "/dev/pts":"/dev/pts",\
166                                 "/usr/portage":self.settings["snapshot_cache_path"]+"/portage",\
167                                 "/usr/portage/distfiles":self.settings["distdir"]}
168                 else:
169                         self.mounts=[ "/proc","/dev","/usr/portage/distfiles" ]
170                         self.mountmap={"/proc":"/proc", "/dev":"/dev", "/dev/pts":"/dev/pts",\
171                                 "/usr/portage/distfiles":self.settings["distdir"]}
172                 if os.uname()[0] == "Linux":
173                         self.mounts.append("/dev/pts")
174
175                 self.set_mounts()
176
177                 # Configure any user specified options (either in catalyst.conf or on
178                 # the command line).
179                 if self.settings.has_key("PKGCACHE"):
180                         self.set_pkgcache_path()
181                         print "Location of the package cache is " + self.settings["pkgcache_path"]
182                         self.mounts.append("/usr/portage/packages")
183                         self.mountmap["/usr/portage/packages"]=self.settings["pkgcache_path"]
184                 
185                 if self.settings.has_key("KERNCACHE"):
186                         self.set_kerncache_path()
187                         print "Location of the kerncache is " + self.settings["kerncache_path"]
188                         self.mounts.append("/tmp/kerncache")
189                         self.mountmap["/tmp/kerncache"]=self.settings["kerncache_path"]
190
191                 if self.settings.has_key("CCACHE"):
192                         if os.environ.has_key("CCACHE_DIR"):
193                                 ccdir=os.environ["CCACHE_DIR"]
194                                 del os.environ["CCACHE_DIR"]
195                         else:
196                                 ccdir="/root/.ccache"
197                         if not os.path.isdir(ccdir):
198                                         raise CatalystError,\
199                                                 "Compiler cache support can't be enabled (can't find "+ccdir+")"
200                         self.mounts.append("/var/tmp/ccache")
201                         self.mountmap["/var/tmp/ccache"]=ccdir
202                         # for the chroot:
203                         self.env["CCACHE_DIR"]="/var/tmp/ccache"        
204
205                 if self.settings.has_key("ICECREAM"):
206                         self.mounts.append("/var/cache/icecream")
207                         self.mountmap["/var/cache/icecream"]="/var/cache/icecream"
208                         self.env["PATH"]="/usr/lib/icecc/bin:"+self.env["PATH"]
209
210         def override_cbuild(self):
211                 if self.makeconf.has_key("CBUILD"):
212                         self.settings["CBUILD"]=self.makeconf["CBUILD"]
213
214         def override_chost(self):
215                 if self.makeconf.has_key("CHOST"):
216                         self.settings["CHOST"]=self.makeconf["CHOST"]
217         
218         def override_cflags(self):
219                 if self.makeconf.has_key("CFLAGS"):
220                         self.settings["CFLAGS"]=self.makeconf["CFLAGS"]
221
222         def override_cxxflags(self):    
223                 if self.makeconf.has_key("CXXFLAGS"):
224                         self.settings["CXXFLAGS"]=self.makeconf["CXXFLAGS"]
225         
226         def override_ldflags(self):
227                 if self.makeconf.has_key("LDFLAGS"):
228                         self.settings["LDFLAGS"]=self.makeconf["LDFLAGS"]
229         
230         def set_install_mask(self):
231                 if self.settings.has_key("install_mask"):
232                         if type(self.settings["install_mask"]) != types.StringType:
233                                 self.settings["install_mask"]=string.join(self.settings["install_mask"])
234         
235         def set_spec_prefix(self):
236                 self.settings["spec_prefix"]=self.settings["target"]
237
238         def set_target_profile(self):
239                 self.settings["target_profile"]=self.settings["profile"]
240         
241         def set_target_subpath(self):
242                 self.settings["target_subpath"]=self.settings["rel_type"]+"/"+self.settings["target"]+\
243                         "-"+self.settings["subarch"]+"-"+self.settings["version_stamp"]
244         
245         def set_source_subpath(self):
246                 if type(self.settings["source_subpath"]) != types.StringType:
247                         raise CatalystError, "source_subpath should have been a string. Perhaps you have something wrong in your spec file?"
248         
249         def set_pkgcache_path(self):
250                 if self.settings.has_key("pkgcache_path"):
251                         if type(self.settings["pkgcache_path"]) != types.StringType:
252                                 self.settings["pkgcache_path"]=normpath(string.join(self.settings["pkgcache_path"]))
253                 else:
254                         self.settings["pkgcache_path"]=normpath(self.settings["storedir"]+"/packages/"+\
255                                 self.settings["target_subpath"]+"/")
256
257         def set_kerncache_path(self):
258                 if self.settings.has_key("kerncache_path"):
259                         if type(self.settings["kerncache_path"]) != types.StringType:
260                                 self.settings["kerncache_path"]=normpath(string.join(self.settings["kerncache_path"]))
261                 else:
262                         self.settings["kerncache_path"]=normpath(self.settings["storedir"]+"/kerncache/"+\
263                                 self.settings["target_subpath"]+"/")
264
265         def set_target_path(self):
266                 self.settings["target_path"]=normpath(self.settings["storedir"]+"/builds/"+\
267                         self.settings["target_subpath"]+".tar.bz2")
268                 if self.settings.has_key("AUTORESUME") \
269                         and os.path.exists(self.settings["autoresume_path"]+"setup_target_path"):
270                         print "Resume point detected, skipping target path setup operation..."
271                 else:
272                         # first clean up any existing target stuff
273                         if os.path.isfile(self.settings["target_path"]):
274                                 cmd("rm -f "+self.settings["target_path"], \
275                                 "Could not remove existing file: "+self.settings["target_path"],env=self.env)
276                                 touch(self.settings["autoresume_path"]+"setup_target_path")
277                 
278                         if not os.path.exists(self.settings["storedir"]+"/builds/"):
279                                 os.makedirs(self.settings["storedir"]+"/builds/")
280
281         def set_archscript(self):
282             if self.settings.has_key(self.settings["spec_prefix"]+"/archscript"):
283                 print "\nWarning!!!  "
284                 print "\t"+self.settings["spec_prefix"]+"/archscript" + " is deprecated and no longer used.\n"
285         def set_runscript(self):
286             if self.settings.has_key(self.settings["spec_prefix"]+"/runscript"):
287                 print "\nWarning!!!  "
288                 print "\t"+self.settings["spec_prefix"]+"/runscript" + " is deprecated and no longer used.\n"
289
290         def set_fsscript(self): 
291                 if self.settings.has_key(self.settings["spec_prefix"]+"/fsscript"):
292                         self.settings["fsscript"]=self.settings[self.settings["spec_prefix"]+"/fsscript"]
293                         del self.settings[self.settings["spec_prefix"]+"/fsscript"]
294         
295         def set_rcadd(self):    
296                 if self.settings.has_key(self.settings["spec_prefix"]+"/rcadd"):
297                         self.settings["rcadd"]=self.settings[self.settings["spec_prefix"]+"/rcadd"]
298                         del self.settings[self.settings["spec_prefix"]+"/rcadd"]
299         
300         def set_rcdel(self):    
301                 if self.settings.has_key(self.settings["spec_prefix"]+"/rcdel"):
302                         self.settings["rcdel"]=self.settings[self.settings["spec_prefix"]+"/rcdel"]
303                         del self.settings[self.settings["spec_prefix"]+"/rcdel"]
304
305         def set_cdtar(self):    
306                 if self.settings.has_key(self.settings["spec_prefix"]+"/cdtar"):
307                         self.settings["cdtar"]=normpath(self.settings[self.settings["spec_prefix"]+"/cdtar"])
308                         del self.settings[self.settings["spec_prefix"]+"/cdtar"]
309         
310         def set_iso(self):      
311                 if self.settings.has_key(self.settings["spec_prefix"]+"/iso"):
312                         self.settings["iso"]=normpath(self.settings[self.settings["spec_prefix"]+"/iso"])
313                         del self.settings[self.settings["spec_prefix"]+"/iso"]
314
315         def set_fstype(self):   
316                 if self.settings.has_key(self.settings["spec_prefix"]+"/cdfstype"):
317                         print "\nWarning!!!  "
318                         print self.settings["spec_prefix"]+"/cdfstype" + " is deprecated and may be removed."
319                         print "\tUse "+self.settings["spec_prefix"]+"/fstype" + " instead."
320                         print "\tConverting to "+self.settings["spec_prefix"]+"/fstype" + " internally."
321                         print "\tContinuing ....\n"
322                         self.settings["fstype"]=self.settings[self.settings["spec_prefix"]+"/cdfstype"]
323                         del self.settings[self.settings["spec_prefix"]+"/cdfstype"]
324                 
325                 if self.settings.has_key(self.settings["spec_prefix"]+"/fstype"):
326                         self.settings["fstype"]=self.settings[self.settings["spec_prefix"]+"/fstype"]
327                         del self.settings[self.settings["spec_prefix"]+"/fstype"]
328
329                 if not self.settings.has_key("fstype"):
330                         self.settings["fstype"]="normal"
331                         for x in self.valid_values:
332                                 if x ==  self.settings["spec_prefix"]+"/fstype" or x == self.settings["spec_prefix"]+"/cdfstype":
333                                         print "\n"+self.settings["spec_prefix"]+"/fstype is being set to the default of \"normal\"\n"
334
335         def set_fsops(self):
336                 if self.settings.has_key("fstype"):
337                         self.valid_values.append("fsops")
338                         if self.settings.has_key(self.settings["spec_prefix"]+"/fsops"):
339                                 self.settings["fsops"]=self.settings[self.settings["spec_prefix"]+"/fsops"]
340                                 del self.settings[self.settings["spec_prefix"]+"/fsops"]
341         
342         def set_source_path(self):
343                 if self.settings.has_key("SEEDCACHE") and os.path.isdir(normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/")):
344                         self.settings["source_path"]=normpath(self.settings["storedir"]+"/tmp/"+self.settings["source_subpath"]+"/")
345                 else:
346                         self.settings["source_path"]=normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2")
347                         if os.path.isfile(self.settings["source_path"]):
348                                 if os.path.exists(self.settings["source_path"]): # XXX: Is this even necessary if the previous check passes?
349                                         self.settings["source_path_hash"]=generate_hash(self.settings["source_path"],\
350                                                 hash_function=self.settings["hash_function"],verbose=False)
351                 print "Source path set to "+self.settings["source_path"]
352                 if os.path.isdir(self.settings["source_path"]):
353                         print "\tIf this is not desired, remove this directory or turn off seedcache in the options of catalyst.conf"
354                         print "\tthe source path will then be "+normpath(self.settings["storedir"]+"/builds/"+self.settings["source_subpath"]+".tar.bz2\n")
355
356         def set_dest_path(self):
357                 if self.settings.has_key("root_path"):
358                         self.settings["destpath"]=normpath(self.settings["chroot_path"]+self.settings["root_path"])
359                 else:
360                         self.settings["destpath"]=normpath(self.settings["chroot_path"])
361
362         def set_cleanables(self):
363                 self.settings["cleanables"]=["/etc/resolv.conf","/var/tmp/*","/tmp/*","/root/*",\
364                                                 "/usr/portage"]
365
366         def set_snapshot_path(self):
367                 self.settings["snapshot_path"]=normpath(self.settings["storedir"]+"/snapshots/portage-"+self.settings["snapshot"]+".tar.bz2")
368                 
369                 if os.path.exists(self.settings["snapshot_path"]):
370                         self.settings["snapshot_path_hash"]=generate_hash(self.settings["snapshot_path"],\
371                                         hash_function=self.settings["hash_function"],verbose=False)
372         
373         def set_snapcache_path(self):
374                 if self.settings.has_key("SNAPCACHE"):
375                         self.settings["snapshot_cache_path"]=normpath(self.settings["snapshot_cache"]+"/"+self.settings["snapshot"]+"/")
376                         self.snapcache_lock=catalyst_lock.LockDir(self.settings["snapshot_cache_path"])
377                         print "Caching snapshot to " + self.settings["snapshot_cache_path"]
378         
379         def set_chroot_path(self):
380                 # Note the trailing slash is very important and things would break without it
381                 self.settings["chroot_path"]=normpath(self.settings["storedir"]+"/tmp/"+self.settings["target_subpath"]+"/")
382                 self.chroot_lock=catalyst_lock.LockDir(self.settings["chroot_path"])
383         
384         def set_autoresume_path(self):
385                 self.settings["autoresume_path"]=normpath(self.settings["storedir"]+"/tmp/"+\
386                         self.settings["rel_type"]+"/"+".autoresume-"+self.settings["target"]+\
387                         "-"+self.settings["subarch"]+"-"+self.settings["version_stamp"]+"/")
388                 if self.settings.has_key("AUTORESUME"):
389                         print "The autoresume path is " + self.settings["autoresume_path"]
390                 if not os.path.exists(self.settings["autoresume_path"]):
391                         os.makedirs(self.settings["autoresume_path"],0755)
392         
393         def set_controller_file(self):
394                 self.settings["controller_file"]=normpath(self.settings["sharedir"]+"/targets/"+self.settings["target"]+"/"+self.settings["target"]+"-controller.sh")
395
396         def set_iso_volume_id(self):
397                 if self.settings.has_key(self.settings["spec_prefix"]+"/volid"):
398                         self.settings["iso_volume_id"] = self.settings[self.settings["spec_prefix"]+"/volid"]
399                         if len(self.settings["iso_volume_id"])>32:
400                                 raise CatalystError,"ISO VOLUME ID: volid must not exceed 32 characters."
401                 else:
402                         self.settings["iso_volume_id"] = "catalyst " + self.settings["snapshot"] 
403                                                                                                                         
404         def set_action_sequence(self):
405                 # Default action sequence for run method
406                 self.settings["action_sequence"]=["unpack","unpack_snapshot",\
407                                 "config_profile_link","setup_confdir","portage_overlay",\
408                                 "base_dirs","bind","chroot_setup","setup_environment",\
409                                 "run_local","preclean","unbind","clean"]
410 #               if self.settings.has_key("TARBALL") or \
411 #                       not self.settings.has_key("FETCH"):
412                 if not self.settings.has_key("FETCH"):
413                         self.settings["action_sequence"].append("capture")
414                 self.settings["action_sequence"].append("clear_autoresume")
415         
416         def set_use(self):
417                 if self.settings.has_key(self.settings["spec_prefix"]+"/use"):
418                         self.settings["use"]=self.settings[self.settings["spec_prefix"]+"/use"]
419                         del self.settings[self.settings["spec_prefix"]+"/use"]
420                 if self.settings.has_key("use"):
421                     if type(self.settings["use"])==types.StringType:
422                         self.settings["use"]=self.settings["use"].split()
423                         self.settings["use"].append("bindist")
424
425         def set_stage_path(self):
426                         self.settings["stage_path"]=normpath(self.settings["chroot_path"])
427         
428         def set_mounts(self):
429                 pass
430
431         def set_packages(self):
432                 pass
433
434         def set_rm(self):
435             if self.settings.has_key(self.settings["spec_prefix"]+"/rm"):
436                 if type(self.settings[self.settings["spec_prefix"]+"/rm"])==types.StringType:
437                     self.settings[self.settings["spec_prefix"]+"/rm"]=self.settings[self.settings["spec_prefix"]+"/rm"].split()
438
439         def set_linuxrc(self):
440             if self.settings.has_key(self.settings["spec_prefix"]+"/linuxrc"):
441                         if type(self.settings[self.settings["spec_prefix"]+"/linuxrc"])==types.StringType:
442                                 self.settings["linuxrc"]=self.settings[self.settings["spec_prefix"]+"/linuxrc"]
443                                 del self.settings[self.settings["spec_prefix"]+"/linuxrc"]
444
445         def set_portage_overlay(self):
446                 if self.settings.has_key("portage_overlay"):
447                         if type(self.settings["portage_overlay"])==types.StringType:
448                                 self.settings["portage_overlay"]=self.settings["portage_overlay"].split()
449                         print "portage_overlay directories are set to: \"" + string.join(self.settings["portage_overlay"])+"\""
450         
451         def set_overlay(self):
452                 if self.settings.has_key(self.settings["spec_prefix"]+"/overlay"):
453                         if type(self.settings[self.settings["spec_prefix"]+"/overlay"])==types.StringType:
454                                 self.settings[self.settings["spec_prefix"]+"/overlay"]=self.settings[self.settings["spec_prefix"]+"/overlay"].split()
455         
456         def set_root_overlay(self):
457                 if self.settings.has_key(self.settings["spec_prefix"]+"/root_overlay"):
458                         if type(self.settings[self.settings["spec_prefix"]+"/root_overlay"])==types.StringType:
459                                 self.settings[self.settings["spec_prefix"]+"/root_overlay"]=self.settings[self.settings["spec_prefix"]+"/root_overlay"].split()
460         
461
462         def set_root_path(self):
463                 # ROOT= variable for emerges
464                 self.settings["root_path"]="/"
465
466         def set_valid_build_kernel_vars(self,addlargs):
467                 if addlargs.has_key("boot/kernel"):
468                         if type(addlargs["boot/kernel"]) == types.StringType:
469                                 loopy=[addlargs["boot/kernel"]]
470                         else:
471                                 loopy=addlargs["boot/kernel"]
472                             
473                         for x in loopy:
474                                 self.required_values.append("boot/kernel/"+x+"/sources")
475                                 self.required_values.append("boot/kernel/"+x+"/config")
476                                 self.valid_values.append("boot/kernel/"+x+"/aliases")
477                                 self.valid_values.append("boot/kernel/"+x+"/extraversion")
478                                 self.valid_values.append("boot/kernel/"+x+"/packages")
479                                 if addlargs.has_key("boot/kernel/"+x+"/packages"):
480                                         if type(addlargs["boot/kernel/"+x+"/packages"]) == types.StringType:
481                                                 addlargs["boot/kernel/"+x+"/packages"]=[addlargs["boot/kernel/"+x+"/packages"]]
482                                 self.valid_values.append("boot/kernel/"+x+"/use")
483                                 self.valid_values.append("boot/kernel/"+x+"/gk_kernargs")
484                                 self.valid_values.append("boot/kernel/"+x+"/gk_action")
485                                 self.valid_values.append("boot/kernel/"+x+"/initramfs_overlay")
486                                 self.valid_values.append("boot/kernel/"+x+"/softlevel")
487                                 self.valid_values.append("boot/kernel/"+x+"/console")
488                                 self.valid_values.append("boot/kernel/"+x+"/machine_type")
489                                 self.valid_values.append("boot/kernel/"+x+"/postconf")
490                                 if addlargs.has_key("boot/kernel/"+x+"/postconf"):
491                                         print "boot/kernel/"+x+"/postconf is deprecated"
492                                         print "\tInternally moving these ebuilds to boot/kernel/"+x+"/packages"
493                                         print "\tPlease move them to boot/kernel/"+x+"/packages in your specfile"
494                                         if type(addlargs["boot/kernel/"+x+"/postconf"]) == types.StringType:
495                                                 loop2=[addlargs["boot/kernel/"+x+"/postconf"]]
496                                         else:
497                                                 loop2=addlargs["boot/kernel/"+x+"/postconf"]
498                                 
499                                         for y in loop2:
500                                                 if not addlargs.has_key("boot/kernel/"+x+"/packages"):
501                                                         addlargs["boot/kernel/"+x+"/packages"]=[y]
502                                                 else:
503                                                         addlargs["boot/kernel/"+x+"/packages"].append(y)
504
505         def set_build_kernel_vars(self):
506             if self.settings.has_key(self.settings["spec_prefix"]+"/devmanager"):
507                 self.settings["devmanager"]=self.settings[self.settings["spec_prefix"]+"/devmanager"]
508                 del self.settings[self.settings["spec_prefix"]+"/devmanager"]
509             
510             if self.settings.has_key(self.settings["spec_prefix"]+"/splashtype"):
511                 self.settings["splashtype"]=self.settings[self.settings["spec_prefix"]+"/splashtype"]
512                 del self.settings[self.settings["spec_prefix"]+"/splashtype"]
513             
514             if self.settings.has_key(self.settings["spec_prefix"]+"/gk_mainargs"):
515                 self.settings["gk_mainargs"]=self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
516                 del self.settings[self.settings["spec_prefix"]+"/gk_mainargs"]
517
518         def kill_chroot_pids(self):
519             print "Checking for processes running in chroot and killing them."
520             
521             # Force environment variables to be exported so script can see them
522             self.setup_environment()
523
524             if os.path.exists(self.settings["sharedir"]+"/targets/support/kill-chroot-pids.sh"):
525                             cmd("/bin/bash "+self.settings["sharedir"]+"/targets/support/kill-chroot-pids.sh",\
526                                                 "kill-chroot-pids script failed.",env=self.env)
527         
528         def mount_safety_check(self):
529                 mypath=self.settings["chroot_path"]
530                 
531                 """
532                 check and verify that none of our paths in mypath are mounted. We don't want to clean
533                 up with things still mounted, and this allows us to check. 
534                 returns 1 on ok, 0 on "something is still mounted" case.
535                 """
536                 if not os.path.exists(mypath):
537                         return
538                 
539                 for x in self.mounts:
540                         if not os.path.exists(mypath+x):
541                                 continue
542                         
543                         if ismount(mypath+x):
544                                 #something is still mounted
545                                 try:
546                                         print x+" is still mounted; performing auto-bind-umount...",
547                                         # try to umount stuff ourselves
548                                         self.unbind()
549                                         if ismount(mypath+x):
550                                                 raise CatalystError, "Auto-unbind failed for "+x
551                                         
552                                         else:
553                                                 print "Auto-unbind successful..."
554                                 
555                                 except CatalystError:
556                                         raise CatalystError, "Unable to auto-unbind "+x
557                 
558         def unpack(self):
559                 unpack=True
560
561                 clst_unpack_hash=read_from_clst(self.settings["autoresume_path"]+"unpack")
562                 
563                 if self.settings.has_key("SEEDCACHE"):
564                         if os.path.isdir(self.settings["source_path"]): 
565                                 # SEEDCACHE Is a directory, use Rsync
566                                 unpack_cmd="rsync -a --delete "+self.settings["source_path"]+" "+self.settings["chroot_path"]
567                                 display_msg="\nStarting rsync from "+self.settings["source_path"]+"\nto "+\
568                                         self.settings["chroot_path"]+" (This may take some time) ...\n"
569                                 error_msg="Rsync of "+self.settings["source_path"]+" to "+self.settings["chroot_path"]+" failed."
570                         else:
571                                 # SEEDCACHE is a not a directory, try untar'ing
572                                 print "Referenced SEEDCACHE does not appear to be a directory, trying to untar..."
573                                 display_msg="\nStarting tar extract from "+self.settings["source_path"]+"\nto "+\
574                                         self.settings["chroot_path"]+" (This may take some time) ...\n"
575                                 unpack_cmd="tar xjpf "+self.settings["source_path"]+" -C "+self.settings["chroot_path"]
576                                 error_msg="Tarball extraction of "+self.settings["source_path"]+" to "+self.settings["chroot_path"]+" failed."
577                 else:
578                         # No SEEDCACHE, use tar
579                         display_msg="\nStarting tar extract from "+self.settings["source_path"]+"\nto "+\
580                                 self.settings["chroot_path"]+" (This may take some time) ...\n"
581                         unpack_cmd="tar xjpf "+self.settings["source_path"]+" -C "+self.settings["chroot_path"]
582                         error_msg="Tarball extraction of "+self.settings["source_path"]+" to "+self.settings["chroot_path"]+" failed."
583                 
584                 
585                 if self.settings.has_key("AUTORESUME"):
586                         # Autoresume is Valid, SeedCache is Valid
587                         if os.path.isdir(self.settings["source_path"]) and os.path.exists(self.settings["autoresume_path"]+"unpack"):
588                                 unpack=False
589                                 invalid_snapshot=False
590                         
591                         # Autoresume is Valid, Tarball is Valid
592                         elif os.path.isfile(self.settings["source_path"]) and self.settings["source_path_hash"] == clst_unpack_hash:
593                                 unpack=False
594                                 invalid_snapshot=True
595                         
596                         # Autoresume is InValid, SeedCache
597                         elif os.path.isdir(self.settings["source_path"]) and not os.path.exists(self.settings["autoresume_path"]+"unpack"):
598                                 unpack=True
599                                 invalid_snapshot=False
600                         
601                         # Autoresume is InValid, Tarball
602                         elif os.path.isfile(self.settings["source_path"]) and self.settings["source_path_hash"] != clst_unpack_hash:
603                                 unpack=True
604                                 invalid_snapshot=True
605                 else:
606                         # No Autoresume,SeedCache
607                         if self.settings.has_key("SEEDCACHE"):
608                                 
609                                 # Seed cache so lets run rsync and rsync can clean up extra junk
610                                 if os.path.isdir(self.settings["source_path"]):
611                                         unpack=True
612                                         invalid_snapshot=False
613                 
614                                 # Tarball so we better unpack and remove anything already there
615                                 elif os.path.isfile(self.settings["source_path"]):
616                                         unpack=True
617                                         invalid_snapshot=True
618                         
619                         # No Autoresume,No SeedCache
620                         else:
621                                 
622                                 # Tarball so we better unpack and remove anything already there
623                                 if os.path.isfile(self.settings["source_path"]):
624                                         unpack=True
625                                         invalid_snapshot=True
626                                 # Should never reach this if so something is very wrong
627                                 elif os.path.isdir(self.settings["source_path"]):
628                                         raise CatalystError,"source path is a dir but seedcache is not enabled"
629
630                 if unpack:
631                         self.mount_safety_check()
632                         
633                         if invalid_snapshot:
634                                 if self.settings.has_key("AUTORESUME"):
635                                         print "No Valid Resume point detected, cleaning up  ..."
636                                 
637                                 self.clear_autoresume()
638                                 self.clear_chroot()
639                         
640                         if not os.path.exists(self.settings["chroot_path"]):
641                                 os.makedirs(self.settings["chroot_path"])
642
643                         if not os.path.exists(self.settings["chroot_path"]+"/tmp"):
644                                 os.makedirs(self.settings["chroot_path"]+"/tmp",1777)
645                         
646                         if self.settings.has_key("PKGCACHE"):   
647                                 if not os.path.exists(self.settings["pkgcache_path"]):
648                                         os.makedirs(self.settings["pkgcache_path"],0755)
649                         
650                         if self.settings.has_key("KERNCACHE"):  
651                                 if not os.path.exists(self.settings["kerncache_path"]):
652                                         os.makedirs(self.settings["kerncache_path"],0755)
653                         
654                         print display_msg
655                         cmd(unpack_cmd,error_msg,env=self.env)
656
657                         if self.settings.has_key("source_path_hash"):
658                                 myf=open(self.settings["autoresume_path"]+"unpack","w")
659                                 myf.write(self.settings["source_path_hash"])
660                                 myf.close()
661                         else:
662                                 touch(self.settings["autoresume_path"]+"unpack")
663                 else:
664                     print "Resume point detected, skipping unpack operation..."
665         
666
667         def unpack_snapshot(self):
668                 unpack=True
669                 snapshot_hash=read_from_clst(self.settings["autoresume_path"]+"unpack_portage")
670                 
671                 if self.settings.has_key("SNAPCACHE"): 
672                         snapshot_cache_hash=read_from_clst(self.settings["snapshot_cache_path"]+"catalyst-hash")
673                         destdir=self.settings["snapshot_cache_path"]
674                         unpack_cmd="tar xjpf "+self.settings["snapshot_path"]+" -C "+destdir
675                         unpack_errmsg="Error unpacking snapshot"
676                         cleanup_msg="Cleaning up invalid snapshot cache at \n\t"+self.settings["snapshot_cache_path"]+" (This can take a long time)..."
677                         cleanup_errmsg="Error removing existing snapshot cache directory."
678                         self.snapshot_lock_object=self.snapcache_lock
679                         
680                         if self.settings["snapshot_path_hash"] == snapshot_cache_hash:
681                                 print "Valid snapshot cache, skipping unpack of portage tree ..."
682                                 unpack=False
683                 
684                 else:
685                         destdir=normpath(self.settings["chroot_path"]+"/usr/portage")
686                         cleanup_errmsg="Error removing existing snapshot directory."
687                         cleanup_msg="Cleaning up existing portage tree (This can take a long time) ..."
688                         unpack_cmd="tar xjpf "+self.settings["snapshot_path"]+" -C "+self.settings["chroot_path"]+"/usr"
689                         unpack_errmsg="Error unpacking snapshot"
690                 
691                         if self.settings.has_key("AUTORESUME") \
692                         and os.path.exists(self.settings["chroot_path"]+"/usr/portage/") \
693                         and os.path.exists(self.settings["autoresume_path"]+"unpack_portage") \
694                         and self.settings["snapshot_path_hash"] == snapshot_hash:
695                                 print "Valid Resume point detected, skipping unpack of portage tree..."
696                                 unpack=False
697                                     
698                 
699                 
700                 if unpack:
701                         if self.settings.has_key("SNAPCACHE"): 
702                             self.snapshot_lock_object.write_lock()
703                         if os.path.exists(destdir):
704                                 print cleanup_msg
705                                 cleanup_cmd="rm -rf "+destdir
706                                 cmd(cleanup_cmd,cleanup_errmsg,env=self.env)
707                         if not os.path.exists(destdir):
708                                 os.makedirs(destdir,0755)
709                         
710                         print "Unpacking portage tree (This can take a long time) ..."
711                         cmd(unpack_cmd,unpack_errmsg,env=self.env)
712
713                         if self.settings.has_key("SNAPCACHE"): 
714                                 myf=open(self.settings["snapshot_cache_path"]+"catalyst-hash","w")
715                                 myf.write(self.settings["snapshot_path_hash"])
716                                 myf.close()
717                         
718                         else:   
719                                 print "Setting snapshot autoresume point"
720                                 myf=open(self.settings["autoresume_path"]+"unpack_portage","w")
721                                 myf.write(self.settings["snapshot_path_hash"])
722                                 myf.close()
723                         
724                         if self.settings.has_key("SNAPCACHE"): 
725                             self.snapshot_lock_object.unlock()
726
727         def config_profile_link(self):
728                 if self.settings.has_key("AUTORESUME") \
729                         and os.path.exists(self.settings["autoresume_path"]+"config_profile_link"):
730                         print "Resume point detected, skipping config_profile_link operation..."
731                 else:
732                         print "Configuring profile link..."
733                         cmd("rm -f "+self.settings["chroot_path"]+"/etc/make.profile",\
734                                         "Error zapping profile link",env=self.env)
735                         cmd("ln -sf ../usr/portage/profiles/"+self.settings["target_profile"]+\
736                                 " "+self.settings["chroot_path"]+"/etc/make.profile","Error creating profile link",env=self.env)
737                         touch(self.settings["autoresume_path"]+"config_profile_link")
738                                        
739         def setup_confdir(self):        
740                 if self.settings.has_key("AUTORESUME") \
741                         and os.path.exists(self.settings["autoresume_path"]+"setup_confdir"):
742                         print "Resume point detected, skipping setup_confdir operation..."
743                 else:
744                         if self.settings.has_key("portage_confdir"):
745                                 print "Configuring /etc/portage..."
746                                 cmd("rm -rf "+self.settings["chroot_path"]+"/etc/portage","Error zapping /etc/portage",env=self.env)
747                                 cmd("cp -R "+self.settings["portage_confdir"]+"/ "+self.settings["chroot_path"]+\
748                                         "/etc/portage","Error copying /etc/portage",env=self.env)
749                                 touch(self.settings["autoresume_path"]+"setup_confdir")
750         
751         def portage_overlay(self):
752             # Here, we copy the contents of our overlays to /usr/local/portage. We
753             # always copy over the overlays in case it has changed.
754             if self.settings.has_key("portage_overlay"):
755                 for x in self.settings["portage_overlay"]: 
756                         if os.path.exists(x):
757                                 print "Copying overlay dir " +x
758                                 cmd("mkdir -p "+self.settings["chroot_path"]+"/usr/local/portage","Could not make portage_overlay dir",env=self.env)
759                                 cmd("cp -R "+x+"/* "+self.settings["chroot_path"]+"/usr/local/portage","Could not copy portage_overlay",env=self.env)
760         
761         def root_overlay(self):
762             # copy over the root_overlay
763             # Always copy over the overlay incase it has changed
764                 if self.settings.has_key(self.settings["spec_prefix"]+"/root_overlay"):
765                         for x in self.settings[self.settings["spec_prefix"]+"/root_overlay"]: 
766                                 if os.path.exists(x):
767                                         print "Copying root_overlay: "+x
768                                         cmd("rsync -a "+x+"/ "+\
769                                                 self.settings["chroot_path"], self.settings["spec_prefix"]+"/root_overlay: "+x+" copy failed.",env=self.env)
770
771         def base_dirs(self):
772                 pass
773
774         def bind(self):
775                 for x in self.mounts: 
776                         if not os.path.exists(self.settings["chroot_path"]+x):
777                                 os.makedirs(self.settings["chroot_path"]+x,0755)
778                         
779                         if not os.path.exists(self.mountmap[x]):
780                                 os.makedirs(self.mountmap[x],0755)
781                         
782                         src=self.mountmap[x]
783                         if self.settings.has_key("SNAPCACHE") and x == "/usr/portage":
784                                 self.snapshot_lock_object.read_lock()
785                         if os.uname()[0] == "FreeBSD":
786                                 if src == "/dev":
787                                         retval=os.system("mount -t devfs none "+self.settings["chroot_path"]+x)
788                                 else:
789                                         retval=os.system("mount_nullfs "+src+" "+self.settings["chroot_path"]+x)
790                         else:
791                                 retval=os.system("mount --bind "+src+" "+self.settings["chroot_path"]+x)
792                         if retval!=0:
793                                 self.unbind()
794                                 raise CatalystError,"Couldn't bind mount "+src
795                             
796         
797         def unbind(self):
798                 ouch=0
799                 mypath=self.settings["chroot_path"]
800                 myrevmounts=self.mounts[:]
801                 myrevmounts.reverse()
802                 # unmount in reverse order for nested bind-mounts
803                 for x in myrevmounts:
804                         if not os.path.exists(mypath+x):
805                                 continue
806                         
807                         if not ismount(mypath+x):
808                                 # it's not mounted, continue
809                                 continue
810                         
811                         retval=os.system("umount "+os.path.join(mypath,x.lstrip(os.path.sep)))
812                         
813                         if retval!=0:
814                                 warn("First attempt to unmount: "+mypath+x+" failed.")
815                                 warn("Killing any pids still running in the chroot")
816                                 
817                                 self.kill_chroot_pids()
818                                 
819                                 retval2=os.system("umount "+mypath+x)
820                                 if retval2!=0:
821                                     ouch=1
822                                     warn("Couldn't umount bind mount: "+mypath+x)
823                                     # keep trying to umount the others, to minimize damage if developer makes a mistake
824                 
825                         if self.settings.has_key("SNAPCACHE") and x == "/usr/portage":
826                                 try:
827                                     # Its possible the snapshot lock object isnt created yet
828                                     # this is because mount safety check calls unbind before the target is fully initialized            
829                                     self.snapshot_lock_object.unlock()
830                                 except:
831                                     pass
832                 if ouch:
833                         """
834                         if any bind mounts really failed, then we need to raise
835                         this to potentially prevent an upcoming bash stage cleanup script
836                         from wiping our bind mounts.
837                         """
838                         raise CatalystError,"Couldn't umount one or more bind-mounts; aborting for safety."
839
840         def chroot_setup(self):
841                 self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/make.conf")
842                 self.override_cbuild()
843                 self.override_chost()
844                 self.override_cflags()
845                 self.override_cxxflags()        
846                 self.override_ldflags() 
847                 if self.settings.has_key("AUTORESUME") \
848                         and os.path.exists(self.settings["autoresume_path"]+"chroot_setup"):
849                         print "Resume point detected, skipping chroot_setup operation..."
850                 else:
851                         print "Setting up chroot..."
852                         
853                         #self.makeconf=read_makeconf(self.settings["chroot_path"]+"/etc/make.conf")
854                         
855                         cmd("cp /etc/resolv.conf "+self.settings["chroot_path"]+"/etc",\
856                                 "Could not copy resolv.conf into place.",env=self.env)
857                 
858                     # copy over the envscript, if applicable
859                         if self.settings.has_key("ENVSCRIPT"):
860                                 if not os.path.exists(self.settings["ENVSCRIPT"]):
861                                         raise CatalystError, "Can't find envscript "+self.settings["ENVSCRIPT"]
862                             
863                                 print "\nWarning!!!!"
864                                 print "\tOverriding certain env variables may cause catastrophic failure."
865                                 print "\tIf your build fails look here first as the possible problem."
866                                 print "\tCatalyst assumes you know what you are doing when setting"
867                                 print "\t\tthese variables."
868                                 print "\tCatalyst Maintainers use VERY minimal envscripts if used at all"
869                                 print "\tYou have been warned\n"
870                                 
871                                 cmd("cp "+self.settings["ENVSCRIPT"]+" "+self.settings["chroot_path"]+"/tmp/envscript",\
872                                         "Could not copy envscript into place.",env=self.env)
873
874                         # Setup metadata_overlay
875                         if self.settings.has_key("METADATA_OVERLAY") and not self.settings.has_key("portage_confdir"):
876                                 if not os.path.exists(self.settings["chroot_path"] + "/etc/portage"):
877                                         cmd("mkdir " + self.settings["chroot_path"] + "/etc/portage")
878                                 myf = open(self.settings["chroot_path"] + "/etc/portage/modules", "a")
879                                 myf.write("portdbapi.auxdbmodule = cache.metadata_overlay.database\n")
880                                 myf.close()
881
882                     # Copy over /etc/hosts from the host in case there are any
883                         # specialties in there
884                         if os.path.exists(self.settings["chroot_path"]+"/etc/hosts"):
885                                 cmd("mv "+self.settings["chroot_path"]+"/etc/hosts "+self.settings["chroot_path"]+\
886                                         "/etc/hosts.bck", "Could not backup /etc/hosts",env=self.env)
887                                 cmd("cp /etc/hosts "+self.settings["chroot_path"]+"/etc/hosts", "Could not copy /etc/hosts",env=self.env)
888                         #self.override_cbuild()
889                         #self.override_chost()
890                         #self.override_cflags()
891                         #self.override_cxxflags()       
892                         #self.override_ldflags()        
893                         # Modify and write out make.conf (for the chroot)
894                         cmd("rm -f "+self.settings["chroot_path"]+"/etc/make.conf","Could not remove "+self.settings["chroot_path"]+"/etc/make.conf",\
895                                 env=self.env)
896                         myf=open(self.settings["chroot_path"]+"/etc/make.conf","w")
897                         myf.write("# These settings were set by the catalyst build script that automatically\n# built this stage.\n")
898                         myf.write("# Please consult /etc/make.conf.example for a more detailed example.\n")
899                         if self.settings.has_key("CFLAGS"):
900                                 myf.write('CFLAGS="'+self.settings["CFLAGS"]+'"\n')
901                         if self.settings.has_key("CXXFLAGS"):
902                                 myf.write('CXXFLAGS="'+self.settings["CXXFLAGS"]+'"\n')
903                         else:
904                                 myf.write('CXXFLAGS="${CFLAGS}"\n')
905                     
906                         if self.settings.has_key("LDFLAGS"):
907                                 myf.write('LDFLAGS="'+self.settings["LDFLAGS"]+'"\n')
908                         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")
909                         if self.settings.has_key("CBUILD"):
910                                 myf.write('CBUILD="'+self.settings["CBUILD"]+'"\n')
911                         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.\nCHOST="'+self.settings["CHOST"]+'"\n')
912                     
913                         # Figure out what our USE vars are for building
914                         myusevars=[]
915                         if self.settings.has_key("HOSTUSE"):
916                                 myusevars.extend(self.settings["HOSTUSE"])
917                 
918                         if self.settings.has_key("use"):
919                                 myusevars.extend(self.settings["use"])
920
921                         if myusevars:
922                                 myf.write('USE="'+string.join(myusevars)+'"\n')
923
924                     # Setup the portage overlay 
925                         if self.settings.has_key("portage_overlay"):
926 #                               myf.write('PORTDIR_OVERLAY="'+string.join(self.settings["portage_overlay"])+'"\n')
927                                 myf.write('PORTDIR_OVERLAY="/usr/local/portage"\n')
928
929                         myf.close()
930                         touch(self.settings["autoresume_path"]+"chroot_setup")
931         
932         def fsscript(self):
933                 if self.settings.has_key("AUTORESUME") \
934                         and os.path.exists(self.settings["autoresume_path"]+"fsscript"):
935                         print "Resume point detected, skipping fsscript operation..."
936                 else:
937                     if self.settings.has_key("fsscript"):
938                         if os.path.exists(self.settings["controller_file"]):
939                             cmd("/bin/bash "+self.settings["controller_file"]+" fsscript","fsscript script failed.",env=self.env)
940                         touch(self.settings["autoresume_path"]+"fsscript")
941
942         def rcupdate(self):
943                 if self.settings.has_key("AUTORESUME") \
944                         and os.path.exists(self.settings["autoresume_path"]+"rcupdate"):
945                         print "Resume point detected, skipping rcupdate operation..."
946                 else:
947                     if os.path.exists(self.settings["controller_file"]):
948                         cmd("/bin/bash "+self.settings["controller_file"]+" rc-update","rc-update script failed.",env=self.env)
949                         touch(self.settings["autoresume_path"]+"rcupdate")
950
951         def clean(self):
952                 if self.settings.has_key("AUTORESUME") \
953                         and os.path.exists(self.settings["autoresume_path"]+"clean"):
954                         print "Resume point detected, skipping clean operation..."
955                 else:
956                     for x in self.settings["cleanables"]: 
957                             print "Cleaning chroot: "+x+"... "
958                             cmd("rm -rf "+self.settings["destpath"]+x,"Couldn't clean "+x,env=self.env)
959
960                     # put /etc/hosts back into place
961                     if os.path.exists(self.settings["chroot_path"]+"/etc/hosts.bck"):
962                                 cmd("mv -f "+self.settings["chroot_path"]+"/etc/hosts.bck "+self.settings["chroot_path"]+"/etc/hosts", "Could not replace /etc/hosts",env=self.env)
963
964                     # remove our overlay
965                     if os.path.exists(self.settings["chroot_path"]+"/usr/local/portage"):
966                                 cmd("rm -rf "+self.settings["chroot_path"]+"/usr/local/portage", "Could not remove /usr/local/portage",env=self.env)
967                                 cmd("sed -i '/^PORTDIR_OVERLAY/d' "+self.settings["chroot_path"]+"/etc/make.conf", "Could not remove PORTDIR_OVERLAY from make.conf",env=self.env)
968
969                     # clean up old and obsoleted files in /etc
970                     if os.path.exists(self.settings["stage_path"]+"/etc"):
971                                 cmd("find "+self.settings["stage_path"]+"/etc -maxdepth 1 -name \"*-\" | xargs rm -f", "Could not remove stray files in /etc",env=self.env)
972
973                     if os.path.exists(self.settings["controller_file"]):
974                         cmd("/bin/bash "+self.settings["controller_file"]+" clean","clean script failed.",env=self.env)
975                         touch(self.settings["autoresume_path"]+"clean")
976         
977         def empty(self):                
978             if self.settings.has_key("AUTORESUME") \
979                 and os.path.exists(self.settings["autoresume_path"]+"empty"):
980                 print "Resume point detected, skipping empty operation..."
981             else:
982                 if self.settings.has_key(self.settings["spec_prefix"]+"/empty"):
983                     if type(self.settings[self.settings["spec_prefix"]+"/empty"])==types.StringType:
984                         self.settings[self.settings["spec_prefix"]+"/empty"]=self.settings[self.settings["spec_prefix"]+"/empty"].split()
985                     for x in self.settings[self.settings["spec_prefix"]+"/empty"]:
986                         myemp=self.settings["destpath"]+x
987                         if not os.path.isdir(myemp):
988                             print x,"not a directory or does not exist, skipping 'empty' operation."
989                             continue
990                         print "Emptying directory",x
991                         # stat the dir, delete the dir, recreate the dir and set
992                         # the proper perms and ownership
993                         mystat=os.stat(myemp)
994                         shutil.rmtree(myemp)
995                         os.makedirs(myemp,0755)
996                         os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
997                         os.chmod(myemp,mystat[ST_MODE])
998                     touch(self.settings["autoresume_path"]+"empty")
999         
1000         def remove(self):
1001             if self.settings.has_key("AUTORESUME") \
1002                 and os.path.exists(self.settings["autoresume_path"]+"remove"):
1003                 print "Resume point detected, skipping remove operation..."
1004             else:
1005                 if self.settings.has_key(self.settings["spec_prefix"]+"/rm"):
1006                     for x in self.settings[self.settings["spec_prefix"]+"/rm"]:
1007                         # we're going to shell out for all these cleaning operations,
1008                         # so we get easy glob handling
1009                         print "livecd: removing "+x
1010                         os.system("rm -rf "+self.settings["chroot_path"]+x)
1011                 try:
1012                     if os.path.exists(self.settings["controller_file"]):
1013                             cmd("/bin/bash "+self.settings["controller_file"]+" clean",\
1014                                 "Clean  failed.",env=self.env)
1015                             touch(self.settings["autoresume_path"]+"remove")
1016                 except:
1017                     self.unbind()
1018                     raise
1019
1020         
1021         def preclean(self):
1022             if self.settings.has_key("AUTORESUME") \
1023                 and os.path.exists(self.settings["autoresume_path"]+"preclean"):
1024                 print "Resume point detected, skipping preclean operation..."
1025             else:
1026                 try:
1027                         if os.path.exists(self.settings["controller_file"]):
1028                                 cmd("/bin/bash "+self.settings["controller_file"]+" preclean","preclean script failed.",env=self.env)
1029                                 touch(self.settings["autoresume_path"]+"preclean")
1030                 
1031                 except:
1032                         self.unbind()
1033                         raise CatalystError, "Build failed, could not execute preclean"
1034
1035         def capture(self):
1036             if self.settings.has_key("AUTORESUME") \
1037                 and os.path.exists(self.settings["autoresume_path"]+"capture"):
1038                 print "Resume point detected, skipping capture operation..."
1039             else:
1040                 """capture target in a tarball"""
1041                 mypath=self.settings["target_path"].split("/")
1042                 # remove filename from path
1043                 mypath=string.join(mypath[:-1],"/")
1044                 
1045                 # now make sure path exists
1046                 if not os.path.exists(mypath):
1047                         os.makedirs(mypath)
1048
1049                 print "Creating stage tarball..."
1050                 
1051                 cmd("tar cjpf "+self.settings["target_path"]+" -C "+self.settings["stage_path"]+\
1052                         " .","Couldn't create stage tarball",env=self.env)
1053
1054                 self.gen_contents_file(self.settings["target_path"])
1055                 self.gen_digest_file(self.settings["target_path"])
1056
1057                 touch(self.settings["autoresume_path"]+"capture")
1058
1059         def run_local(self):
1060             if self.settings.has_key("AUTORESUME") \
1061                 and os.path.exists(self.settings["autoresume_path"]+"run_local"):
1062                 print "Resume point detected, skipping run_local operation..."
1063             else:
1064                 try:
1065                         if os.path.exists(self.settings["controller_file"]):
1066                                 cmd("/bin/bash "+self.settings["controller_file"]+" run","run script failed.",env=self.env)
1067                                 touch(self.settings["autoresume_path"]+"run_local")
1068
1069                 except CatalystError:
1070                         self.unbind()
1071                         raise CatalystError,"Stage build aborting due to error."
1072         
1073         def setup_environment(self):
1074                 # Modify the current environment. This is an ugly hack that should be
1075                 # fixed. We need this to use the os.system() call since we can't
1076                 # specify our own environ:
1077                 for x in self.settings.keys():
1078                         # sanitize var names by doing "s|/-.|_|g"
1079                         varname="clst_"+string.replace(x,"/","_")
1080                         varname=string.replace(varname,"-","_")
1081                         varname=string.replace(varname,".","_")
1082                         if type(self.settings[x])==types.StringType:
1083                                 # prefix to prevent namespace clashes:
1084                                 #os.environ[varname]=self.settings[x]
1085                                 self.env[varname]=self.settings[x]
1086                         elif type(self.settings[x])==types.ListType:
1087                                 #os.environ[varname]=string.join(self.settings[x])
1088                                 self.env[varname]=string.join(self.settings[x])
1089                         elif type(self.settings[x])==types.BooleanType:
1090                                 if self.settings[x]:
1091                                         self.env[varname]="true"
1092                                 else:
1093                                         self.env[varname]="false"
1094                 if self.settings.has_key("makeopts"):
1095                         self.env["MAKEOPTS"]=self.settings["makeopts"]
1096                         
1097         def run(self):
1098                 self.chroot_lock.write_lock()
1099
1100                 # Kill any pids in the chroot
1101                 self.kill_chroot_pids()
1102
1103                 # Check for mounts right away and abort if we cannot unmount them.
1104                 self.mount_safety_check()
1105
1106                 if self.settings.has_key("CLEAR_AUTORESUME"):
1107                         self.clear_autoresume()
1108                 if self.settings.has_key("PURGE"):
1109                         self.purge()
1110
1111                 for x in self.settings["action_sequence"]:
1112                         print "--- Running action sequence: "+x
1113                         sys.stdout.flush()
1114                         try:
1115                                 apply(getattr(self,x))
1116                         except:
1117                                 self.mount_safety_check()
1118                                 raise
1119                 
1120                 self.chroot_lock.unlock()
1121
1122         def unmerge(self):
1123             if self.settings.has_key("AUTORESUME") \
1124                 and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
1125                     print "Resume point detected, skipping unmerge operation..."
1126             else:
1127                 if self.settings.has_key(self.settings["spec_prefix"]+"/unmerge"):
1128                     if type(self.settings[self.settings["spec_prefix"]+"/unmerge"])==types.StringType:
1129                         self.settings[self.settings["spec_prefix"]+"/unmerge"]=[self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1130                     myunmerge=self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1131                     
1132                     for x in range(0,len(myunmerge)):
1133                     #surround args with quotes for passing to bash,
1134                     #allows things like "<" to remain intact
1135                         myunmerge[x]="'"+myunmerge[x]+"'"
1136                     myunmerge=string.join(myunmerge)
1137                     
1138                     #before cleaning, unmerge stuff:
1139                     try:
1140                         cmd("/bin/bash "+self.settings["controller_file"]+" unmerge "+ myunmerge,\
1141                                 "Unmerge script failed.",env=self.env)
1142                         #cmd("/bin/bash "+self.settings["sharedir"]+"/targets/" \
1143                         #       +self.settings["target"]+"/unmerge.sh "+myunmerge,"Unmerge script failed.",env=self.env)
1144                         print "unmerge shell script"
1145                     except CatalystError:
1146                         self.unbind()
1147                         raise
1148
1149                 touch(self.settings["autoresume_path"]+"unmerge")
1150
1151         def target_setup(self):
1152             if self.settings.has_key("AUTORESUME") \
1153                 and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
1154                     print "Resume point detected, skipping target_setup operation..."
1155             else:
1156                 print "Setting up filesystems per filesystem type"
1157                 cmd("/bin/bash "+self.settings["controller_file"]+" target_image_setup "+ self.settings["target_path"],\
1158                                 "target_image_setup script failed.",env=self.env)
1159                 touch(self.settings["autoresume_path"]+"target_setup")
1160         
1161         def setup_overlay(self):        
1162                 if self.settings.has_key("AUTORESUME") \
1163                 and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
1164                         print "Resume point detected, skipping setup_overlay operation..."
1165                 else:
1166                         if self.settings.has_key(self.settings["spec_prefix"]+"/overlay"):
1167                                 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]: 
1168                                         if os.path.exists(x):
1169                                                 cmd("rsync -a "+x+"/ "+\
1170                                                         self.settings["target_path"], self.settings["spec_prefix"]+"overlay: "+x+" copy failed.",env=self.env)
1171                                 touch(self.settings["autoresume_path"]+"setup_overlay")
1172         
1173         def create_iso(self):
1174             if self.settings.has_key("AUTORESUME") \
1175                 and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
1176                     print "Resume point detected, skipping create_iso operation..."
1177             else:
1178                 # create the ISO - this is the preferred method (the iso scripts do not always work)
1179                 if self.settings.has_key("iso"):
1180                         cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1181                                 self.settings["iso"],"ISO creation script failed.",env=self.env)
1182                         self.gen_contents_file(self.settings["iso"])
1183                         self.gen_digest_file(self.settings["iso"])
1184                         touch(self.settings["autoresume_path"]+"create_iso")
1185                 
1186                 
1187                 else:
1188                         print "WARNING livecd/iso was not defined."
1189                         print "A CD Image will not be created, skipping create-iso.sh..."
1190
1191
1192         def build_packages(self):
1193             if self.settings.has_key("AUTORESUME") \
1194                 and os.path.exists(self.settings["autoresume_path"]+"build_packages"):
1195                     print "Resume point detected, skipping build_packages operation..."
1196             else:
1197                 if self.settings.has_key(self.settings["spec_prefix"]+"/packages"):
1198                         if self.settings.has_key("AUTORESUME") \
1199                                 and os.path.exists(self.settings["autoresume_path"]+"build_packages"):
1200                                         print "Resume point detected, skipping build_packages operation..."
1201                         else:
1202                                 mypack=list_bashify(self.settings[self.settings["spec_prefix"]+"/packages"])
1203                                 try:
1204                                         cmd("/bin/bash "+self.settings["controller_file"]+\
1205                                                 " build_packages "+mypack,"Error in attempt to build packages",env=self.env)
1206                                         touch(self.settings["autoresume_path"]+"build_packages")
1207                                 except CatalystError:
1208                                         self.unbind()
1209                                         raise CatalystError,self.settings["spec_prefix"] + "build aborting due to error."
1210         
1211         def build_kernel(self):
1212                 if self.settings.has_key("AUTORESUME") \
1213                 and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
1214                         print "Resume point detected, skipping build_kernel operation..."
1215                 else:
1216                         if self.settings.has_key("boot/kernel"):
1217                                 try:
1218                                         mynames=self.settings["boot/kernel"]
1219                                         if type(mynames)==types.StringType:
1220                                                 mynames=[mynames]
1221                                         # execute the script that sets up the kernel build environment
1222                                         cmd("/bin/bash "+self.settings["controller_file"]+" pre-kmerge ",\
1223                                                 "Runscript pre-kmerge failed",env=self.env)
1224                 
1225                                         for kname in mynames:
1226                                                 if self.settings.has_key("AUTORESUME") \
1227                                                         and os.path.exists(self.settings["autoresume_path"]+"build_kernel_"+kname):
1228                                                         print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1229                                                 else:
1230                                                         try:
1231                                                                 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1232                                                                         self.unbind()
1233                                                                         raise CatalystError, "Can't find kernel config: " \
1234                                                                                 +self.settings["boot/kernel/"+kname+"/config"]
1235
1236                                                         except TypeError:
1237                                                                 raise CatalystError, "Required value boot/kernel/config not specified"
1238                         
1239                                                         try:
1240                                                                 cmd("cp "+self.settings["boot/kernel/"+kname+"/config"]+" "+ \
1241                                                                         self.settings["chroot_path"]+"/var/tmp/"+kname+".config", \
1242                                                                         "Couldn't copy kernel config: "+self.settings["boot/kernel/"+kname+"/config"],\
1243                                                                         env=self.env)
1244
1245                                                         except CatalystError:
1246                                                                 self.unbind()
1247
1248                                                         # If we need to pass special options to the bootloader
1249                                                         # for this kernel put them into the environment.
1250                                                         if self.settings.has_key("boot/kernel/"+kname+"/kernelopts"):
1251                                                                 myopts=self.settings["boot/kernel/"+kname+"/kernelopts"]
1252                                 
1253                                                                 if type(myopts) != types.StringType:
1254                                                                         myopts = string.join(myopts)
1255                                                                         self.env[kname+"_kernelopts"]=myopts
1256
1257                                                                 else:
1258                                                                         self.env[kname+"_kernelopts"]=""
1259                                             
1260                                                         if not self.settings.has_key("boot/kernel/"+kname+"/extraversion"):
1261                                                                 self.settings["boot/kernel/"+kname+"/extraversion"]=""
1262                                                 
1263                                                         self.env["clst_kextraversion"]=self.settings["boot/kernel/"+kname+"/extraversion"]
1264
1265                                                         if self.settings.has_key("boot/kernel/"+kname+"/initramfs_overlay"):
1266                                                                 if os.path.exists(self.settings["boot/kernel/"+kname+"/initramfs_overlay"]):
1267                                                                         print "Copying initramfs_overlay dir " +self.settings["boot/kernel/"+kname+"/initramfs_overlay"]
1268
1269                                                                         cmd("mkdir -p "+self.settings["chroot_path"]+"/tmp/initramfs_overlay/" + \
1270                                                                                 self.settings["boot/kernel/"+kname+"/initramfs_overlay"],env=self.env)
1271                                                 
1272                                                                         cmd("cp -R "+self.settings["boot/kernel/"+kname+"/initramfs_overlay"]+"/* " + \
1273                                                                                 self.settings["chroot_path"] + "/tmp/initramfs_overlay/" + \
1274                                                                                 self.settings["boot/kernel/"+kname+"/initramfs_overlay"],\
1275                                                                                 env=self.env)
1276         
1277
1278                                                         # execute the script that builds the kernel
1279                                                         cmd("/bin/bash "+self.settings["controller_file"]+" kernel "+kname,\
1280                                                                 "Runscript kernel build failed",env=self.env)
1281                                         
1282                                                         if self.settings.has_key("boot/kernel/"+kname+"/initramfs_overlay"):
1283                                                                 if os.path.exists(self.settings["chroot_path"]+"/tmp/initramfs_overlay/"):
1284                                                                         print "Cleaning up temporary overlay dir"
1285                                                                         cmd("rm -R "+self.settings["chroot_path"]+"/tmp/initramfs_overlay/",env=self.env)
1286
1287                                                         touch(self.settings["autoresume_path"]+"build_kernel_"+kname)
1288
1289                                                         # execute the script that cleans up the kernel build environment
1290                                                         cmd("/bin/bash "+self.settings["controller_file"]+" post-kmerge ",\
1291                                                                 "Runscript post-kmerge failed",env=self.env)
1292                                 
1293                                         touch(self.settings["autoresume_path"]+"build_kernel")
1294                         
1295                                 except CatalystError:
1296                                         self.unbind()
1297                                         raise CatalystError,"build aborting due to kernel build error."
1298
1299         def bootloader(self):
1300             if self.settings.has_key("AUTORESUME") \
1301                 and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
1302                     print "Resume point detected, skipping bootloader operation..."
1303             else:
1304                 try:
1305                         cmd("/bin/bash "+self.settings["controller_file"]+" bootloader " + self.settings["target_path"],\
1306                                 "Bootloader runscript failed.",env=self.env)
1307                         touch(self.settings["autoresume_path"]+"bootloader")
1308                 except CatalystError:
1309                         self.unbind()
1310                         raise CatalystError,"Runscript aborting due to error."
1311
1312         def livecd_update(self):
1313             if self.settings.has_key("AUTORESUME") \
1314                 and os.path.exists(self.settings["autoresume_path"]+"livecd_update"):
1315                     print "Resume point detected, skipping build_packages operation..."
1316             else:
1317                 try:
1318                         cmd("/bin/bash "+self.settings["controller_file"]+" livecd-update",\
1319                                 "livecd-update failed.",env=self.env)
1320                         touch(self.settings["autoresume_path"]+"livecd_update")
1321                 
1322                 except CatalystError:
1323                         self.unbind()
1324                         raise CatalystError,"build aborting due to livecd_update error."
1325
1326         def clear_chroot(self):
1327                 myemp=self.settings["chroot_path"]
1328                 if os.path.isdir(myemp):
1329                     print "Emptying directory",myemp
1330                     # stat the dir, delete the dir, recreate the dir and set
1331                     # the proper perms and ownership
1332                     mystat=os.stat(myemp)
1333                     #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1334                     if os.uname()[0] == "FreeBSD": # There's no easy way to change flags recursively in python
1335                             os.system("chflags -R noschg "+myemp)
1336                     shutil.rmtree(myemp)
1337                     os.makedirs(myemp,0755)
1338                     os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1339                     os.chmod(myemp,mystat[ST_MODE])
1340         
1341         def clear_packages(self):
1342             if self.settings.has_key("PKGCACHE"):
1343                 print "purging the pkgcache ..."
1344
1345                 myemp=self.settings["pkgcache_path"]
1346                 if os.path.isdir(myemp):
1347                     print "Emptying directory",myemp
1348                     # stat the dir, delete the dir, recreate the dir and set
1349                     # the proper perms and ownership
1350                     mystat=os.stat(myemp)
1351                     #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1352                     shutil.rmtree(myemp)
1353                     os.makedirs(myemp,0755)
1354                     os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1355                     os.chmod(myemp,mystat[ST_MODE])
1356         
1357         def clear_kerncache(self):
1358             if self.settings.has_key("KERNCACHE"):
1359                 print "purging the kerncache ..."
1360
1361                 myemp=self.settings["kerncache_path"]
1362                 if os.path.isdir(myemp):
1363                     print "Emptying directory",myemp
1364                     # stat the dir, delete the dir, recreate the dir and set
1365                     # the proper perms and ownership
1366                     mystat=os.stat(myemp)
1367                     #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1368                     shutil.rmtree(myemp)
1369                     os.makedirs(myemp,0755)
1370                     os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1371                     os.chmod(myemp,mystat[ST_MODE])
1372         
1373         def clear_autoresume(self):
1374                 # clean resume points since they are no longer needed
1375                 if self.settings.has_key("AUTORESUME"):
1376                         print "Removing AutoResume Points: ..."
1377                 myemp=self.settings["autoresume_path"]
1378                 if os.path.isdir(myemp):
1379                                 if self.settings.has_key("AUTORESUME"):
1380                                         print "Emptying directory",myemp
1381                                 # stat the dir, delete the dir, recreate the dir and set
1382                                 # the proper perms and ownership
1383                                 mystat=os.stat(myemp)
1384                                 if os.uname()[0] == "FreeBSD":
1385                                         cmd("chflags -R noschg "+myemp, "Could not remove immutable flag for file " + myemp)
1386                                 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1387                                 shutil.rmtree(myemp)
1388                                 os.makedirs(myemp,0755)
1389                                 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1390                                 os.chmod(myemp,mystat[ST_MODE])
1391
1392
1393         def gen_contents_file(self,file):
1394                 if os.path.exists(file+".CONTENTS"):
1395                         os.remove(file+".CONTENTS")
1396                 if self.settings.has_key("contents"):
1397                         if os.path.exists(file):
1398                                 myf=open(file+".CONTENTS","w")
1399                                 keys={}
1400                                 for i in self.settings["contents"].split():
1401                                         keys[i]=1
1402                                         array=keys.keys()
1403                                         array.sort()
1404                                 for j in array:
1405                                         contents=generate_contents(file,contents_function=j,verbose=self.settings.has_key("VERBOSE"))
1406                                         myf.write(contents)
1407                                 myf.close()
1408
1409         def gen_digest_file(self,file):
1410                 if os.path.exists(file+".DIGESTS"):
1411                         os.remove(file+".DIGESTS")
1412                 if self.settings.has_key("digests"):
1413                         if os.path.exists(file):
1414                                 myf=open(file+".DIGESTS","w")
1415                                 keys={}
1416                                 for i in self.settings["digests"].split():
1417                                         keys[i]=1
1418                                         array=keys.keys()
1419                                         array.sort()
1420                                 for f in [file, file+'.CONTENTS']:
1421                                         if os.path.exists(f):
1422                                                 for j in array:
1423                                                         hash=generate_hash(f,hash_function=j,verbose=self.settings.has_key("VERBOSE"))
1424                                                         myf.write(hash)
1425                                 myf.close()
1426
1427         def purge(self):
1428             countdown(10,"Purging Caches ...")
1429             if self.settings.has_key("PURGE"):
1430                 print "clearing autoresume ..."
1431                 self.clear_autoresume()
1432                 
1433                 print "clearing chroot ..."
1434                 self.clear_chroot()
1435                 
1436                 print "clearing package cache ..."
1437                 self.clear_packages()
1438                 
1439                 print "clearing kerncache ..."
1440                 self.clear_kerncache()
1441
1442 #vim: ts=4 sw=4 sta et sts=4 ai