Remove the necessity to append do_ to commands to clean up UI.
[bitbake.git] / bin / oemake
1 #!/usr/bin/python
2
3 import string, sys, os
4 sys.path.append('/usr/share/oe')
5 from oe import *
6 import oe
7
8 class PkgBase(event.Event):
9         """Base class for package events"""
10
11         def __init__(self, t, d = {}):
12                 self.pkg = t
13                 self.data = d
14
15         def getPkg(self):
16                 return self._pkg
17
18         def setPkg(self, pkg):
19                 self._pkg = pkg
20
21         pkg = property(getPkg, setPkg, None, "pkg property")
22
23         def getData(self):
24                 return self._data
25
26         def setData(self, data):
27                 self._data = data
28
29         data = property(getData, setData, None, "data property")
30
31 class BuildBase(event.Event):
32         """Base class for oemake run events"""
33
34         def __init__(self, n, p, c):
35                 self.name = n
36                 self.pkgs = p
37                 self.cfg = c
38
39         def getPkgs(self):
40                 return self._pkgs
41
42         def setPkgs(self, pkgs):
43                 self._pkgs = pkgs
44
45         pkgs = property(getPkgs, setPkgs, None, "pkgs property")
46
47         def getName(self):
48                 return self._name
49
50         def setName(self, name):
51                 self._name = name
52
53         name = property(getName, setName, None, "name property")
54
55         def getCfg(self):
56                 return self._cfg
57
58         def setCfg(self, cfg):
59                 self._cfg = cfg
60
61         cfg = property(getCfg, setCfg, None, "cfg property")
62
63 class DepBase(PkgBase):
64         """Base class for dependency events"""
65
66         def __init__(self, t, data, d):
67                 self.dep = d
68                 PkgBase.__init__(self, t, data)
69
70         def getDep(self):
71                 return self._dep
72
73         def setDep(self, dep):
74                 self._dep = dep
75
76         dep = property(getDep, setDep, None, "dep property")
77         
78 class PkgStarted(PkgBase):
79         """Package build started"""
80
81 class PkgFailed(PkgBase):
82         """Package build failed"""
83
84 class PkgSucceeded(PkgBase):
85         """Package build succeeded"""
86
87 class BuildStarted(BuildBase):
88         """oemake build run started"""
89
90 class BuildCompleted(BuildBase):
91         """oemake build run completed"""
92
93 class UnsatisfiedDep(DepBase):
94         """Unsatisfied Dependency"""
95
96 class RecursiveDep(DepBase):
97         """Recursive Dependency"""
98
99 class MultipleProviders(PkgBase):
100         """Multiple Providers"""
101
102 __build_cache_fail = []
103 __build_cache = []
104 def build(graph, item):
105         if item in __build_cache:
106                 return 1
107         if item in __build_cache_fail:
108                 return 0
109         fn = pkgs[item][1]
110         if fn is None:
111                 return 1
112         command = cmd
113         debug(1, "oebuild %s %s" % (command, fn))
114         event.fire(PkgStarted(item, pkgdata[fn]))
115         ret = os.system("oebuild %s %s" % (command, fn))
116         if ret == 0:
117                 event.fire(PkgSucceeded(item, pkgdata[fn]))
118                 __build_cache.append(item)
119                 return 1
120         else:
121                 event.fire(PkgFailed(item, pkgdata[fn]))
122                 __build_cache_fail.append(item)
123                 return 0
124
125 def usage():
126         print "Usage: oemake [options] [oefile ...]"
127 #       print "Run TASK on OEFILE or standard input if OEFILE is -."
128         print "Run OEBuild's build task on a set of oe files, following"
129         print "inter-package dependencies."
130         print "Also obtains .oe files to build from the OEFILES environment variable."
131         print "Example: oemake content/glibc-2.3.1.oe content/patcher-1.0.oe"
132         print ""
133         print "  %s\t\t%s" % ("-v, --version", "output version information and exit")
134         sys.exit(0)
135
136 __version__ = 1.0
137 def version():
138         print "OpenEmbedded Build Infrastructure Core version %s" % oe.__version__
139         print "OEMake version %s" % __version__
140
141 def get_oefiles():
142         """Get default oefiles"""
143         dirs = os.listdir(os.getcwd())
144         oefiles = []
145         for f in dirs:
146                 (root, ext) = os.path.splitext(f)
147                 if ext == ".oe":
148                         oefiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
149         return oefiles
150
151 def get_oefile():
152         """Get default oefile"""
153         oefiles = get_oefiles()
154         if len(oefiles):
155                 return oefiles[0]
156         else:
157                 return None
158
159
160 import getopt
161 try:
162         (opts, args) = getopt.getopt(sys.argv[1:], 'vc:', [ 'version', 'cmd:' ])
163 except getopt.GetoptError:
164         usage()
165
166 # handle opts
167 optsonly = [ opt for (opt,val) in opts]
168 cmd = None
169
170 def getopthash(l):
171         h = {}
172         for (opt, val) in l:
173                 h[opt] = val
174         return h
175
176 opthash = getopthash(opts)
177
178 if opthash.has_key('--version') or opthash.has_key('-v'):
179         version()
180         sys.exit(0)
181
182 if opthash.has_key('--cmd'):
183         cmd = opthash['--cmd']
184 if opthash.has_key('-c'):
185         cmd = opthash['-c']
186
187 _depcmds = { "clean": None,
188              "mrproper": None,
189              "build": "stage", }
190
191 if not cmd:
192         cmd = "build"
193
194 if _depcmds.has_key(cmd):
195         depcmd=_depcmds[cmd]
196 else:
197         depcmd=cmd
198
199 pkgdata = {}
200 pkgs = {}
201 cfg = {}
202 graph = digraph()
203
204 try:
205         cfg = parse.handle("conf/oe.conf", cfg) # Read configuration
206 except IOError:
207         fatal("Unable to open oe.conf")
208
209 if not data.getVar("BUILDNAME", cfg):
210         data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), cfg)
211
212 buildname = data.getVar("BUILDNAME", cfg)
213
214 # grab oefiles
215 files = string.split(data.getVar("OEFILES", cfg, 1) or "")
216 files += args
217 data.setVar("OEFILES", string.join(files), cfg)
218
219 if not len(files):
220         files = get_oefiles()
221
222 if not len(files):
223         usage()
224
225 #set_automatic_vars(sys.argv[2], )                      # Deduce per-package environment variables
226
227 #pkg = [ "pkgname", "depends", "provides" ]
228
229 import glob
230 for f in files:
231         globbed = glob.glob(f) or [ f ]
232         if globbed:
233                 if [ f ] != globbed:
234                         files += globbed
235                         continue
236         # read a file's metadata
237         try:
238                 from copy import deepcopy
239                 pkgdata[f] = parse.handle(f, deepcopy(cfg))
240                 deps = None
241                 if pkgdata[f] is not None:
242                         # allow metadata files to add items to OEFILES
243                         data.update_data(pkgdata[f])
244                         addoefiles = data.getVar('OEFILES', pkgdata[f]) or None
245                         if addoefiles:
246                                 for aof in string.split(addoefiles):
247                                         if not files.count(aof):
248                                                 if not os.path.isabs(aof):
249                                                         aof = os.path.join(os.path.dirname(f),aof)
250                                                 files.append(aof)
251                         for var in pkgdata[f].keys():
252                                 if data.getVarFlag(var, "handler", pkgdata[f]) and data.getVar(var, pkgdata[f]):
253                                         event.register(data.getVar(var, pkgdata[f]))
254                         depstr = data.getVar("DEPENDS", pkgdata[f], 1)
255                         if depstr is not None:
256                                 deps = depstr.split()
257                         pkg = []
258                         pkg.append(data.getVar('CATEGORY', pkgdata[f], 1))
259                         pkg.append(data.getVar('PN', pkgdata[f], 1))
260                         pkg.append(data.getVar('PV', pkgdata[f], 1))
261                         pkg.append(data.getVar('PR', pkgdata[f], 1))
262                         root = "%s/%s-%s-%s" % (pkg[0], pkg[1], pkg[2], pkg[3])
263                         provides = []
264                         # w/ category
265                         provides.append("%s/%s-%s" % (pkg[0], pkg[1], pkg[2]))
266                         provides.append("%s/%s" % (pkg[0], pkg[1]))
267                         # w/o category
268                         provides.append("%s" % pkg[1])
269                         provides.append("%s-%s" % (pkg[1], pkg[2]))
270                         provides.append("%s-%s-%s" % (pkg[1], pkg[2], pkg[3]))
271                         providestr = data.getVar("PROVIDES", pkgdata[f])
272                         if providestr is not None:
273                                 provides += providestr.split()
274                         for provide in provides:
275                                 pkgs[provide] = [[root], None]
276                         pkgs[root] = [deps, f]
277         except IOError:
278                 print "error opening %s" % f
279                 pass
280
281 # add every provide relationship to the dependency graph, depending
282 # on all the packages that provide it
283
284 global __tokill
285 global __unsatisfied
286 __tokill = []
287 __unsatisfied = []
288
289 for pkg in pkgs.keys():
290         graph.addnode(pkg, None)
291
292 for pkg in pkgs.keys():
293         (deps, fn) = pkgs[pkg]
294         if _depcmds[cmd] is not None:
295                 if deps is not None:
296                         for d in deps:
297                                 if not graph.hasnode(d):
298                                         def killitem(graph, item):
299                                                 global __tokill
300                                                 __tokill.append(item)
301                                         graph.walkup(pkg, killitem)
302                                         __unsatisfied.append([pkg, d])
303                                         break
304                                 graph.addnode(pkg, d)
305
306 for u in __unsatisfied:
307         event.fire(UnsatisfiedDep(u[0], pkgdata[pkgs[u[0]][1]], u[1]))
308
309 for k in __tokill:
310         def reallykillitem(graph, item):
311                 graph.delnode(item)
312         graph.walkup(k, reallykillitem)
313
314 event.fire(BuildStarted(buildname, graph.okeys, cfg))
315
316 for k in graph.okeys:
317         graph.walkdown(k, build)
318
319 event.fire(BuildCompleted(buildname, graph.okeys, cfg))