Use /usr/bin/env to locate python.
[bitbake.git] / bin / oemake
1 #!/usr/bin/env 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         opts = ""
116         if force:
117                 opts += " --force"
118         ret = os.system("oebuild %s %s %s" % (opts, command, fn))
119         if ret == 0:
120                 event.fire(PkgSucceeded(item, pkgdata[fn]))
121                 __build_cache.append(item)
122                 return 1
123         else:
124                 event.fire(PkgFailed(item, pkgdata[fn]))
125                 __build_cache_fail.append(item)
126                 return 0
127
128 def usage():
129         print "Usage: oemake [options] [package ...]"
130         print ""
131         print "Builds specified packages, expecting that the .oe files"
132         print "it has to work from are in OEFILES"
133         print "Default packages are all packages in OEFILES."
134         print "Default OEFILES are the .oe files in the current directory."
135         print "Example: oemake glibc"
136         print "Example: oemake ncurses-5.3"
137         print ""
138         print "  %s\t\t%s" % ("-v, --version", "output version information and exit")
139         print "  %s\t\t%s" % ("-c [arg], --cmd [arg]", "specify command to pass to oebuild")
140         print "  %s\t\t%s" % ("-a, --abort", "abort build if any package build fails")
141         print "  %s\t\t%s" % ("-f, --force", "force run of specified cmd, regardless of status")
142         sys.exit(0)
143
144 __version__ = 1.1
145 def version():
146         print "OpenEmbedded Build Infrastructure Core version %s" % oe.__version__
147         print "OEMake version %s" % __version__
148
149 def get_oefiles():
150         """Get default oefiles"""
151         dirs = os.listdir(os.getcwd())
152         oefiles = []
153         for f in dirs:
154                 (root, ext) = os.path.splitext(f)
155                 if ext == ".oe":
156                         oefiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
157         return oefiles
158
159 def get_oefile():
160         """Get default oefile"""
161         oefiles = get_oefiles()
162         if len(oefiles):
163                 return oefiles[0]
164         else:
165                 return None
166
167 def load_oefile(oefile, cfgdata):
168         oepath = data.getVar('OEPATH', cfg)
169         topdir = data.getVar('TOPDIR', cfg)
170         if not topdir:
171                 topdir = os.path.abspath(os.getcwd())
172                 # set topdir to here
173                 data.setVar('TOPDIR', topdir, cfg)
174         oefile = os.path.abspath(oefile)
175         oefile_loc = os.path.abspath(os.path.dirname(oefile))
176         # expand tmpdir to include this topdir
177         data.setVar('TMPDIR', data.getVar('TMPDIR', cfg, 1) or "", cfg)
178         # add topdir to oepath
179         oepath += ":%s" % topdir
180         # set topdir to location of .oe file
181         topdir = oefile_loc
182         #data.setVar('TOPDIR', topdir, cfg)
183         # add that topdir to oepath
184         oepath += ":%s" % topdir
185         # go there
186         oldpath = os.path.abspath(os.getcwd())
187         os.chdir(topdir)
188         data.setVar('OEPATH', oepath, cfg)
189         from copy import deepcopy
190         oe = deepcopy(cfgdata)
191         try:
192                 parse.handle(oefile, oe) # read .oe data
193                 os.chdir(oldpath)
194                 return oe
195         except IOError, OSError:
196                 os.chdir(oldpath)
197                 return None
198
199 import getopt
200 try:
201         (opts, args) = getopt.getopt(sys.argv[1:], 'vc:fa', [ 'version', 'cmd=', 'abort', 'force' ])
202 except getopt.GetoptError:
203         usage()
204
205 # handle opts
206 optsonly = [ opt for (opt,val) in opts]
207 cmd = None
208
209 def getopthash(l):
210         h = {}
211         for (opt, val) in l:
212                 h[opt] = val
213         return h
214
215 opthash = getopthash(opts)
216
217 if opthash.has_key('--version') or opthash.has_key('-v'):
218         version()
219         sys.exit(0)
220
221 if opthash.has_key('--abort') or opthash.has_key('-a'):
222         abort = 1
223 else:
224         abort = 0
225
226 if opthash.has_key('--force') or opthash.has_key('-f'):
227         force = 1
228 else:
229         force = 0
230
231 if opthash.has_key('--cmd'):
232         cmd = opthash['--cmd']
233 if opthash.has_key('-c'):
234         cmd = opthash['-c']
235
236 _depcmds = { "clean": None,
237              "mrproper": None,
238              "build": "stage" }
239
240 if not cmd:
241         cmd = "build"
242
243 if _depcmds.has_key(cmd):
244         depcmd=_depcmds[cmd]
245 else:
246         depcmd=cmd
247
248 pkgdata = {}
249 pkgs = {}
250 cfg = {}
251 graph = digraph()
252
253 try:
254         cfg = parse.handle("conf/oe.conf", cfg) # Read configuration
255 except IOError:
256         fatal("Unable to open oe.conf")
257
258 if not data.getVar("BUILDNAME", cfg):
259         data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), cfg)
260
261 buildname = data.getVar("BUILDNAME", cfg)
262
263 # grab oefiles
264 files = string.split(data.getVar("OEFILES", cfg, 1) or "")
265 data.setVar("OEFILES", string.join(files), cfg)
266
267 if not len(files):
268         files = get_oefiles()
269
270 if not len(files):
271         usage()
272
273 import glob
274 for f in files:
275         globbed = glob.glob(f) or [ f ]
276         if globbed:
277                 if [ f ] != globbed:
278                         files += globbed
279                         continue
280         # read a file's metadata
281         try:
282                 from copy import deepcopy
283                 pkgdata[f] = load_oefile(f, cfg)
284                 deps = None
285                 if pkgdata[f] is not None:
286                         # allow metadata files to add items to OEFILES
287                         #data.update_data(pkgdata[f])
288                         addoefiles = data.getVar('OEFILES', pkgdata[f]) or None
289                         if addoefiles:
290                                 for aof in string.split(addoefiles):
291                                         if not files.count(aof):
292                                                 if not os.path.isabs(aof):
293                                                         aof = os.path.join(os.path.dirname(f),aof)
294                                                 files.append(aof)
295                         for var in pkgdata[f].keys():
296                                 if data.getVarFlag(var, "handler", pkgdata[f]) and data.getVar(var, pkgdata[f]):
297                                         event.register(data.getVar(var, pkgdata[f]))
298                         depstr = data.getVar("DEPENDS", pkgdata[f], 1)
299                         if depstr is not None:
300                                 deps = depstr.split()
301                         pkg = []
302                         pkg.append(data.getVar('CATEGORY', pkgdata[f], 1))
303                         pkg.append(data.getVar('PN', pkgdata[f], 1))
304                         pkg.append(data.getVar('PV', pkgdata[f], 1))
305                         pkg.append(data.getVar('PR', pkgdata[f], 1))
306                         root = "%s/%s-%s-%s" % (pkg[0], pkg[1], pkg[2], pkg[3])
307                         provides = []
308                         providestr = data.getVar("PROVIDES", pkgdata[f], 1)
309                         if providestr is not None:
310                                 provides += providestr.split()
311                         for provide in provides:
312                                 pkgs[provide] = [[root], None]
313                         pkgs[root] = [deps, f]
314         except IOError:
315                 print "error opening %s" % f
316                 pass
317
318 # add every provide relationship to the dependency graph, depending
319 # on all the packages that provide it
320
321 global __tokill
322 global __unsatisfied
323 __tokill = []
324 __unsatisfied = []
325
326 for pkg in pkgs.keys():
327         graph.addnode(pkg, None)
328
329 for pkg in pkgs.keys():
330         (deps, fn) = pkgs[pkg]
331         if depcmd is not None:
332                 if deps is not None:
333                         for d in deps:
334                                 if not graph.hasnode(d):
335                                         def killitem(graph, item):
336                                                 global __tokill
337                                                 __tokill.append(item)
338                                         graph.walkup(pkg, killitem)
339                                         __unsatisfied.append([pkg, d])
340                                         break
341                                 graph.addnode(pkg, d)
342
343 for u in __unsatisfied:
344         event.fire(UnsatisfiedDep(u[0], pkgdata[pkgs[u[0]][1]], u[1]))
345
346 for k in __tokill:
347         def reallykillitem(graph, item):
348                 graph.delnode(item)
349         graph.walkup(k, reallykillitem)
350
351 event.fire(BuildStarted(buildname, graph.okeys, cfg))
352
353 pkgs_to_build = None
354 if args:
355         if not pkgs_to_build:
356                 pkgs_to_build = []
357         pkgs_to_build.extend(args)
358 if not pkgs_to_build:
359         oepkgs = data.getVar('OEPKGS', cfg, 1)
360         if oepkgs:
361                 pkgs_to_build = string.split(oepkgs)
362 if not pkgs_to_build:
363         pkgs_to_build = graph.okeys
364 debug(1, "building: %s" % pkgs_to_build)
365
366 for k in pkgs_to_build:
367         if pkgs.has_key(k):
368                 ret = graph.walkdown(k, build)
369                 if abort and not ret:
370                         oe.fatal("Build of %s failed, aborting." % k)
371         else:
372                 oe.error("Unable to build %s: no .oe file provides it." % k)
373                 if abort:
374                         sys.exit(1)
375 event.fire(BuildCompleted(buildname, graph.okeys, cfg))