03aeb0a1f6e1dec2ea0c381ab43c9eaa2f1f1803
[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 various
29                 # 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 of 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 it.\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_digest_file(self.settings["target_path"])
1055
1056                 touch(self.settings["autoresume_path"]+"capture")
1057
1058         def run_local(self):
1059             if self.settings.has_key("AUTORESUME") \
1060                 and os.path.exists(self.settings["autoresume_path"]+"run_local"):
1061                 print "Resume point detected, skipping run_local operation..."
1062             else:
1063                 try:
1064                         if os.path.exists(self.settings["controller_file"]):
1065                                 cmd("/bin/bash "+self.settings["controller_file"]+" run","run script failed.",env=self.env)
1066                                 touch(self.settings["autoresume_path"]+"run_local")
1067
1068                 except CatalystError:
1069                         self.unbind()
1070                         raise CatalystError,"Stage build aborting due to error."
1071         
1072         def setup_environment(self):
1073                 # Modify the current environment. This is an ugly hack that should be
1074                 # fixed. We need this to use the os.system() call since we can't
1075                 # specify our own environ:
1076                 for x in self.settings.keys():
1077                         # sanitize var names by doing "s|/-.|_|g"
1078                         varname="clst_"+string.replace(x,"/","_")
1079                         varname=string.replace(varname,"-","_")
1080                         varname=string.replace(varname,".","_")
1081                         if type(self.settings[x])==types.StringType:
1082                                 # prefix to prevent namespace clashes:
1083                                 #os.environ[varname]=self.settings[x]
1084                                 self.env[varname]=self.settings[x]
1085                         elif type(self.settings[x])==types.ListType:
1086                                 #os.environ[varname]=string.join(self.settings[x])
1087                                 self.env[varname]=string.join(self.settings[x])
1088                         elif type(self.settings[x])==types.BooleanType:
1089                                 if self.settings[x]:
1090                                         self.env[varname]="true"
1091                                 else:
1092                                         self.env[varname]="false"
1093                 if self.settings.has_key("makeopts"):
1094                         self.env["MAKEOPTS"]=self.settings["makeopts"]
1095                         
1096         def run(self):
1097                 self.chroot_lock.write_lock()
1098
1099                 # Kill any pids in the chroot
1100                 self.kill_chroot_pids()
1101
1102                 # Check for mounts right away and abort if we cannot unmount them.
1103                 self.mount_safety_check()
1104
1105                 if self.settings.has_key("CLEAR_AUTORESUME"):
1106                         self.clear_autoresume()
1107                 if self.settings.has_key("PURGE"):
1108                         self.purge()
1109
1110                 for x in self.settings["action_sequence"]:
1111                         print "--- Running action sequence: "+x
1112                         sys.stdout.flush()
1113                         try:
1114                                 apply(getattr(self,x))
1115                         except:
1116                                 self.mount_safety_check()
1117                                 raise
1118                 
1119                 self.chroot_lock.unlock()
1120
1121         def unmerge(self):
1122             if self.settings.has_key("AUTORESUME") \
1123                 and os.path.exists(self.settings["autoresume_path"]+"unmerge"):
1124                     print "Resume point detected, skipping unmerge operation..."
1125             else:
1126                 if self.settings.has_key(self.settings["spec_prefix"]+"/unmerge"):
1127                     if type(self.settings[self.settings["spec_prefix"]+"/unmerge"])==types.StringType:
1128                         self.settings[self.settings["spec_prefix"]+"/unmerge"]=[self.settings[self.settings["spec_prefix"]+"/unmerge"]]
1129                     myunmerge=self.settings[self.settings["spec_prefix"]+"/unmerge"][:]
1130                     
1131                     for x in range(0,len(myunmerge)):
1132                     #surround args with quotes for passing to bash,
1133                     #allows things like "<" to remain intact
1134                         myunmerge[x]="'"+myunmerge[x]+"'"
1135                     myunmerge=string.join(myunmerge)
1136                     
1137                     #before cleaning, unmerge stuff:
1138                     try:
1139                         cmd("/bin/bash "+self.settings["controller_file"]+" unmerge "+ myunmerge,\
1140                                 "Unmerge script failed.",env=self.env)
1141                         #cmd("/bin/bash "+self.settings["sharedir"]+"/targets/" \
1142                         #       +self.settings["target"]+"/unmerge.sh "+myunmerge,"Unmerge script failed.",env=self.env)
1143                         print "unmerge shell script"
1144                     except CatalystError:
1145                         self.unbind()
1146                         raise
1147
1148                 touch(self.settings["autoresume_path"]+"unmerge")
1149
1150         def target_setup(self):
1151             if self.settings.has_key("AUTORESUME") \
1152                 and os.path.exists(self.settings["autoresume_path"]+"target_setup"):
1153                     print "Resume point detected, skipping target_setup operation..."
1154             else:
1155                 print "Setting up filesystems per filesystem type"
1156                 cmd("/bin/bash "+self.settings["controller_file"]+" target_image_setup "+ self.settings["target_path"],\
1157                                 "target_image_setup script failed.",env=self.env)
1158                 touch(self.settings["autoresume_path"]+"target_setup")
1159         
1160         def setup_overlay(self):        
1161                 if self.settings.has_key("AUTORESUME") \
1162                 and os.path.exists(self.settings["autoresume_path"]+"setup_overlay"):
1163                         print "Resume point detected, skipping setup_overlay operation..."
1164                 else:
1165                         if self.settings.has_key(self.settings["spec_prefix"]+"/overlay"):
1166                                 for x in self.settings[self.settings["spec_prefix"]+"/overlay"]: 
1167                                         if os.path.exists(x):
1168                                                 cmd("rsync -a "+x+"/ "+\
1169                                                         self.settings["target_path"], self.settings["spec_prefix"]+"overlay: "+x+" copy failed.",env=self.env)
1170                                 touch(self.settings["autoresume_path"]+"setup_overlay")
1171         
1172         def create_iso(self):
1173             if self.settings.has_key("AUTORESUME") \
1174                 and os.path.exists(self.settings["autoresume_path"]+"create_iso"):
1175                     print "Resume point detected, skipping create_iso operation..."
1176             else:
1177                 # create the ISO - this is the preferred method (the iso scripts do not always work)
1178                 if self.settings.has_key("iso"):
1179                         cmd("/bin/bash "+self.settings["controller_file"]+" iso "+\
1180                                 self.settings["iso"],"ISO creation script failed.",env=self.env)
1181                         self.gen_digest_file(self.settings["iso"])
1182                         touch(self.settings["autoresume_path"]+"create_iso")
1183                 
1184                 
1185                 else:
1186                         print "WARNING livecd/iso was not defined."
1187                         print "A CD Image will not be created, skipping create-iso.sh..."
1188
1189
1190         def build_packages(self):
1191             if self.settings.has_key("AUTORESUME") \
1192                 and os.path.exists(self.settings["autoresume_path"]+"build_packages"):
1193                     print "Resume point detected, skipping build_packages operation..."
1194             else:
1195                 if self.settings.has_key(self.settings["spec_prefix"]+"/packages"):
1196                         if self.settings.has_key("AUTORESUME") \
1197                                 and os.path.exists(self.settings["autoresume_path"]+"build_packages"):
1198                                         print "Resume point detected, skipping build_packages operation..."
1199                         else:
1200                                 mypack=list_bashify(self.settings[self.settings["spec_prefix"]+"/packages"])
1201                                 try:
1202                                         cmd("/bin/bash "+self.settings["controller_file"]+\
1203                                                 " build_packages "+mypack,"Error in attempt to build packages",env=self.env)
1204                                         touch(self.settings["autoresume_path"]+"build_packages")
1205                                 except CatalystError:
1206                                         self.unbind()
1207                                         raise CatalystError,self.settings["spec_prefix"] + "build aborting due to error."
1208         
1209         def build_kernel(self):
1210                 if self.settings.has_key("AUTORESUME") \
1211                 and os.path.exists(self.settings["autoresume_path"]+"build_kernel"):
1212                         print "Resume point detected, skipping build_kernel operation..."
1213                 else:
1214                         if self.settings.has_key("boot/kernel"):
1215                                 try:
1216                                         mynames=self.settings["boot/kernel"]
1217                                         if type(mynames)==types.StringType:
1218                                                 mynames=[mynames]
1219                                         # execute the script that sets up the kernel build environment
1220                                         cmd("/bin/bash "+self.settings["controller_file"]+" pre-kmerge ",\
1221                                                 "Runscript pre-kmerge failed",env=self.env)
1222                 
1223                                         for kname in mynames:
1224                                                 if self.settings.has_key("AUTORESUME") \
1225                                                         and os.path.exists(self.settings["autoresume_path"]+"build_kernel_"+kname):
1226                                                         print "Resume point detected, skipping build_kernel for "+kname+" operation..."
1227                                                 else:
1228                                                         try:
1229                                                                 if not os.path.exists(self.settings["boot/kernel/"+kname+"/config"]):
1230                                                                         self.unbind()
1231                                                                         raise CatalystError, "Can't find kernel config: " \
1232                                                                                 +self.settings["boot/kernel/"+kname+"/config"]
1233
1234                                                         except TypeError:
1235                                                                 raise CatalystError, "Required value boot/kernel/config not specified"
1236                         
1237                                                         try:
1238                                                                 cmd("cp "+self.settings["boot/kernel/"+kname+"/config"]+" "+ \
1239                                                                         self.settings["chroot_path"]+"/var/tmp/"+kname+".config", \
1240                                                                         "Couldn't copy kernel config: "+self.settings["boot/kernel/"+kname+"/config"],\
1241                                                                         env=self.env)
1242
1243                                                         except CatalystError:
1244                                                                 self.unbind()
1245
1246                                                         # If we need to pass special options to the bootloader
1247                                                         # for this kernel put them into the environment.
1248                                                         if self.settings.has_key("boot/kernel/"+kname+"/kernelopts"):
1249                                                                 myopts=self.settings["boot/kernel/"+kname+"/kernelopts"]
1250                                 
1251                                                                 if type(myopts) != types.StringType:
1252                                                                         myopts = string.join(myopts)
1253                                                                         self.env[kname+"_kernelopts"]=myopts
1254
1255                                                                 else:
1256                                                                         self.env[kname+"_kernelopts"]=""
1257                                             
1258                                                         if not self.settings.has_key("boot/kernel/"+kname+"/extraversion"):
1259                                                                 self.settings["boot/kernel/"+kname+"/extraversion"]=""
1260                                                 
1261                                                         self.env["clst_kextraversion"]=self.settings["boot/kernel/"+kname+"/extraversion"]
1262
1263                                                         if self.settings.has_key("boot/kernel/"+kname+"/initramfs_overlay"):
1264                                                                 if os.path.exists(self.settings["boot/kernel/"+kname+"/initramfs_overlay"]):
1265                                                                         print "Copying initramfs_overlay dir " +self.settings["boot/kernel/"+kname+"/initramfs_overlay"]
1266
1267                                                                         cmd("mkdir -p "+self.settings["chroot_path"]+"/tmp/initramfs_overlay/" + \
1268                                                                                 self.settings["boot/kernel/"+kname+"/initramfs_overlay"],env=self.env)
1269                                                 
1270                                                                         cmd("cp -R "+self.settings["boot/kernel/"+kname+"/initramfs_overlay"]+"/* " + \
1271                                                                                 self.settings["chroot_path"] + "/tmp/initramfs_overlay/" + \
1272                                                                                 self.settings["boot/kernel/"+kname+"/initramfs_overlay"],\
1273                                                                                 env=self.env)
1274         
1275
1276                                                         # execute the script that builds the kernel
1277                                                         cmd("/bin/bash "+self.settings["controller_file"]+" kernel "+kname,\
1278                                                                 "Runscript kernel build failed",env=self.env)
1279                                         
1280                                                         if self.settings.has_key("boot/kernel/"+kname+"/initramfs_overlay"):
1281                                                                 if os.path.exists(self.settings["chroot_path"]+"/tmp/initramfs_overlay/"):
1282                                                                         print "Cleaning up temporary overlay dir"
1283                                                                         cmd("rm -R "+self.settings["chroot_path"]+"/tmp/initramfs_overlay/",env=self.env)
1284
1285                                                         touch(self.settings["autoresume_path"]+"build_kernel_"+kname)
1286
1287                                                         # execute the script that cleans up the kernel build environment
1288                                                         cmd("/bin/bash "+self.settings["controller_file"]+" post-kmerge ",\
1289                                                                 "Runscript post-kmerge failed",env=self.env)
1290                                 
1291                                         touch(self.settings["autoresume_path"]+"build_kernel")
1292                         
1293                                 except CatalystError:
1294                                         self.unbind()
1295                                         raise CatalystError,"build aborting due to kernel build error."
1296
1297         def bootloader(self):
1298             if self.settings.has_key("AUTORESUME") \
1299                 and os.path.exists(self.settings["autoresume_path"]+"bootloader"):
1300                     print "Resume point detected, skipping bootloader operation..."
1301             else:
1302                 try:
1303                         cmd("/bin/bash "+self.settings["controller_file"]+" bootloader " + self.settings["target_path"],\
1304                                 "Bootloader runscript failed.",env=self.env)
1305                         touch(self.settings["autoresume_path"]+"bootloader")
1306                 except CatalystError:
1307                         self.unbind()
1308                         raise CatalystError,"Runscript aborting due to error."
1309
1310         def livecd_update(self):
1311             if self.settings.has_key("AUTORESUME") \
1312                 and os.path.exists(self.settings["autoresume_path"]+"livecd_update"):
1313                     print "Resume point detected, skipping build_packages operation..."
1314             else:
1315                 try:
1316                         cmd("/bin/bash "+self.settings["controller_file"]+" livecd-update",\
1317                                 "livecd-update failed.",env=self.env)
1318                         touch(self.settings["autoresume_path"]+"livecd_update")
1319                 
1320                 except CatalystError:
1321                         self.unbind()
1322                         raise CatalystError,"build aborting due to livecd_update error."
1323
1324         def clear_chroot(self):
1325                 myemp=self.settings["chroot_path"]
1326                 if os.path.isdir(myemp):
1327                     print "Emptying directory",myemp
1328                     # stat the dir, delete the dir, recreate the dir and set
1329                     # the proper perms and ownership
1330                     mystat=os.stat(myemp)
1331                     #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1332                     if os.uname()[0] == "FreeBSD": # There's no easy way to change flags recursively in python
1333                             os.system("chflags -R noschg "+myemp)
1334                     shutil.rmtree(myemp)
1335                     os.makedirs(myemp,0755)
1336                     os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1337                     os.chmod(myemp,mystat[ST_MODE])
1338         
1339         def clear_packages(self):
1340             if self.settings.has_key("PKGCACHE"):
1341                 print "purging the pkgcache ..."
1342
1343                 myemp=self.settings["pkgcache_path"]
1344                 if os.path.isdir(myemp):
1345                     print "Emptying directory",myemp
1346                     # stat the dir, delete the dir, recreate the dir and set
1347                     # the proper perms and ownership
1348                     mystat=os.stat(myemp)
1349                     #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1350                     shutil.rmtree(myemp)
1351                     os.makedirs(myemp,0755)
1352                     os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1353                     os.chmod(myemp,mystat[ST_MODE])
1354         
1355         def clear_kerncache(self):
1356             if self.settings.has_key("KERNCACHE"):
1357                 print "purging the kerncache ..."
1358
1359                 myemp=self.settings["kerncache_path"]
1360                 if os.path.isdir(myemp):
1361                     print "Emptying directory",myemp
1362                     # stat the dir, delete the dir, recreate the dir and set
1363                     # the proper perms and ownership
1364                     mystat=os.stat(myemp)
1365                     #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env=self.env)
1366                     shutil.rmtree(myemp)
1367                     os.makedirs(myemp,0755)
1368                     os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1369                     os.chmod(myemp,mystat[ST_MODE])
1370         
1371         def clear_autoresume(self):
1372                 # clean resume points since they are no longer needed
1373                 if self.settings.has_key("AUTORESUME"):
1374                         print "Removing AutoResume Points: ..."
1375                 myemp=self.settings["autoresume_path"]
1376                 if os.path.isdir(myemp):
1377                                 if self.settings.has_key("AUTORESUME"):
1378                                         print "Emptying directory",myemp
1379                                 # stat the dir, delete the dir, recreate the dir and set
1380                                 # the proper perms and ownership
1381                                 mystat=os.stat(myemp)
1382                                 if os.uname()[0] == "FreeBSD":
1383                                         cmd("chflags -R noschg "+myemp, "Could not remove immutable flag for file " + myemp)
1384                                 #cmd("rm -rf "+myemp, "Could not remove existing file: "+myemp,env-self.env)
1385                                 shutil.rmtree(myemp)
1386                                 os.makedirs(myemp,0755)
1387                                 os.chown(myemp,mystat[ST_UID],mystat[ST_GID])
1388                                 os.chmod(myemp,mystat[ST_MODE])
1389
1390         def gen_digest_file(self,file):
1391                 if os.path.exists(file+".DIGESTS"):
1392                         os.remove(file+".DIGESTS")
1393                 if self.settings.has_key("digests"):
1394                         if os.path.exists(file):
1395                                 myf=open(file+".DIGESTS","w")
1396                                 keys={}
1397                                 for i in self.settings["digests"].split():
1398                                         keys[i]=1
1399                                         array=keys.keys()
1400                                         array.sort()
1401                                 for j in array:
1402                                         if self.settings.has_key("VERBOSE"):
1403                                                 hash=generate_hash(file,hash_function=j,verbose=True)
1404                                         else:
1405                                                 hash=generate_hash(file,hash_function=j)
1406                                         myf.write(hash)
1407                                 myf.close()
1408
1409         def purge(self):
1410             countdown(10,"Purging Caches ...")
1411             if self.settings.has_key("PURGE"):
1412                 print "clearing autoresume ..."
1413                 self.clear_autoresume()
1414                 
1415                 print "clearing chroot ..."
1416                 self.clear_chroot()
1417                 
1418                 print "clearing package cache ..."
1419                 self.clear_packages()
1420                 
1421                 print "clearing kerncache ..."
1422                 self.clear_kerncache()
1423
1424 #vim: ts=4 sw=4 sta et sts=4 ai