mods?
[catalyst.git] / catalyst
1 #!/usr/bin/python
2
3 import os,sys,imp,string
4
5 def die(msg=None):
6         if msg:
7                 print "catalyst: "+msg
8         sys.exit(1)
9
10 def warn(msg):
11         print "catalyst: "+msg
12
13 def usage():
14         print "usage: meep!"
15
16 if len(sys.argv)==1 or sys.argv[1] in ["-h","--help"]:
17         usage()
18         sys.exit(1)
19
20 def arg_parse(mydict, myvalids):
21         "very wimpy argument parsing, just for the prototype"
22         for x in sys.argv[1:]:
23                 foo=string.split(x,"=")
24                 if len(foo)!=2:
25                         die("Invalid arg syntax: "+x)
26                 else:
27                         if foo[0] not in myvalids:
28                                 die("Invalid arg name: "+foo[0])
29                         mydict[foo[0]]=foo[1]
30                         
31 def spec_dump(myspec):
32         for x in myspec.keys():
33                 print x+": "+repr(myspec[x])
34
35 """
36 Overview of catalyst operation
37 ==============================
38
39 * The program starts, and the local machine type is detected. 
40
41 * Based on this information, catalyst determines what kind of machine types
42   it can build for (amd64 and ia64 can build for x86 as well, for example.)
43   The appropriate arch plugins are loaded, which contain builder classes
44   for each supported sub-arch.
45
46 * Command-line arguments are parsed. If specified, a spec file is read.
47
48 * These build variables are stored in an internal "spec" object, which will
49   be a standard python dictionary. This spec dictionary contains all relevant
50   build-related information.
51
52 * The spec object is passed to the appropriate subarch builder constructor.
53   The subarch builder constructor updates the spec object with variables
54   relevant to the sub-arch (pentium4, g3, etc.)
55
56 * The spec object is passed to the appropriate target constructor.
57   The target constructor updates the spec object to contain data relevant
58   to the particular target (stage1, stage3, grp, etc.)
59
60 *** PROTOTYPE CODE UP TO HERE IS COMPLETE (drobbins, 26 Oct '03)
61
62 * The full data of the spec object is written to disc, so there is a complete
63   record of all variables that will be used to build what we're building.  This
64   will allow for another person to re-use this information to replicate our
65   work (it should be possible to distribute a spec file along with a portage
66   snapshot and a starter tarball, and our build can be replicated exactly on
67   any machine.) The spec object contains data like CFLAGS, CHOST, subarch,
68   mainarch, the profile used to build, and for GRP and LiveCDs the complete
69   package build list. This is important to allow work to be replicated. It's
70   possible that the stage1/2/3.sh and other scripts should be distributed as
71   well, to allow proper replication of work.
72
73 * The build process begins by calling the appropriate method of the builder
74   instance. This includes cleanup, setup of chroot, entering the chroot,
75   running the appropriate bash build script, checking for error conditions,
76   and finishing up.
77   
78 * The catalyst process is now complete :)
79 """
80
81 #This allows plugins to import modules in the /modules dir
82 sys.path.append(os.getcwd()+"/modules")
83
84 #map current machine information from uname() to the mainarch we are running
85 #under
86
87 machinemap={    "i386" : "x86",
88                 "i486" : "x86",
89                 "i586" : "x86",
90                 "i686" : "x86",
91                 "x86_64" : "amd64"
92         }
93
94 # map the mainarch we are running under to the mainarches we support for
95 # building stages and LiveCDs. (for example, on amd64, we can build stages for
96 # x86 or amd64.
97
98 targetmap={     "x86" : ["x86"],
99                 "amd64" : ["x86","amd64"]
100         }
101                 
102 mymachine=os.uname()[4]
103 if not machinemap.has_key(mymachine):
104         print "Unknown machine type:",mymachine
105         sys.exit(1)
106 hostarch=machinemap[mymachine]
107 print "Host architecture:",hostarch
108 print "Supported architectures for targets:",string.join(targetmap[hostarch])
109 print "Loading plugins:",
110 archmap={}
111 subarchmap={}
112 for x in targetmap[hostarch]:
113         fh=open("arch/"+x+".py")
114         #this next line loads the plugin as a module and assigns it to archmap[x]
115         archmap[x]=imp.load_module(x,fh,"arch/"+x+".py",(".py","r",imp.PY_SOURCE))
116         #this next line registers all the subarches supported in the plugin
117         archmap[x].register(subarchmap)
118         fh.close()      
119         print x,
120 print
121 print "Available subarches:",string.join(subarchmap.keys())
122
123 import targets
124 targetmap={}
125 targets.register(targetmap)
126
127 print "Available targets:",string.join(targetmap.keys())
128
129 if os.getuid()!=0:
130         #non-root callers can't go any further than here. 
131         die("This script requires root privileges to operate.") 
132
133 #the spec begins!
134 validspec=["version_stamp","target","subarch","rel_type","rel_version","snapshot","source_subpath"]
135 myspec={}
136
137 """
138 local variables from spec:
139
140 version_stamp                   20031016                                        user (from spec)
141 target                          stage3                                          user (from spec)
142 subarch                         pentium4                                        user (from spec)
143 rel_type                        default                                         user (from spec) (was BUILDTYPE)
144 rel_version                     1.4                                             user (from spec) (was MAINVERSION)
145 snapshot                        20031016                                        user (from spec)
146 source_subpath                  default-x86-1.4/stage2-pentium4-20031016        user (from spec)
147 """
148
149 arg_parse(myspec,validspec)
150 #need to verify that we have all required args here. Leaving this out for the prototype.
151 if myspec["subarch"] not in subarchmap.keys():
152         die("Sub-arch "+myspec["subarch"]+" not available.")
153
154 #call builder constructor:
155 mybuilder=subarchmap[myspec["subarch"]](myspec)
156 if myspec["target"] not in targetmap.keys():
157         die("Target "+myspec["target"]+" not available.")
158
159 #these would come from /etc/catalyst.conf:
160 myspec["storedir"]="/var/tmp/catalyst"
161 myspec["sharedir"]="/usr/share/catalyst"
162 #these would come from there too?:
163 myspec["distdir"]="/usr/portage/distfiles"
164 myspec["portdir"]="/usr/portage"
165
166 #call target constructor:
167 mytarget=targetmap[myspec["target"]](myspec)
168 print
169 spec_dump(myspec)
170
171 #to test this program, type:
172
173 # ./catalyst subarch=pentium4 version_stamp=20031016 target=stage3 rel_type=default rel_version=1.4 snapshot=20031016 source_subpath=default-x86-1.4/stage2-pentium4-20031016
174