BUGFIX: follow deps when using --cmd install
[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         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 import getopt
168 try:
169         (opts, args) = getopt.getopt(sys.argv[1:], 'vc:fa', [ 'version', 'cmd=', 'abort', 'force' ])
170 except getopt.GetoptError:
171         usage()
172
173 # handle opts
174 optsonly = [ opt for (opt,val) in opts]
175 cmd = None
176
177 def getopthash(l):
178         h = {}
179         for (opt, val) in l:
180                 h[opt] = val
181         return h
182
183 opthash = getopthash(opts)
184
185 if opthash.has_key('--version') or opthash.has_key('-v'):
186         version()
187         sys.exit(0)
188
189 if opthash.has_key('--abort') or opthash.has_key('-a'):
190         abort = 1
191 else:
192         abort = 0
193
194 if opthash.has_key('--force') or opthash.has_key('-f'):
195         force = 1
196 else:
197         force = 0
198
199 if opthash.has_key('--cmd'):
200         cmd = opthash['--cmd']
201 if opthash.has_key('-c'):
202         cmd = opthash['-c']
203
204 _depcmds = { "clean": None,
205              "mrproper": None,
206              "build": "stage" }
207
208 if not cmd:
209         cmd = "build"
210
211 if _depcmds.has_key(cmd):
212         depcmd=_depcmds[cmd]
213 else:
214         depcmd=cmd
215
216 pkgdata = {}
217 pkgs = {}
218 cfg = {}
219 graph = digraph()
220
221 try:
222         cfg = parse.handle("conf/oe.conf", cfg) # Read configuration
223 except IOError:
224         fatal("Unable to open oe.conf")
225
226 if not data.getVar("BUILDNAME", cfg):
227         data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), cfg)
228
229 buildname = data.getVar("BUILDNAME", cfg)
230
231 # grab oefiles
232 files = string.split(data.getVar("OEFILES", cfg, 1) or "")
233 data.setVar("OEFILES", string.join(files), cfg)
234
235 if not len(files):
236         files = get_oefiles()
237
238 if not len(files):
239         usage()
240
241 import glob
242 for f in files:
243         globbed = glob.glob(f) or [ f ]
244         if globbed:
245                 if [ f ] != globbed:
246                         files += globbed
247                         continue
248         # read a file's metadata
249         try:
250                 from copy import deepcopy
251                 pkgdata[f] = parse.handle(f, deepcopy(cfg))
252                 deps = None
253                 if pkgdata[f] is not None:
254                         # allow metadata files to add items to OEFILES
255                         data.update_data(pkgdata[f])
256                         addoefiles = data.getVar('OEFILES', pkgdata[f]) or None
257                         if addoefiles:
258                                 for aof in string.split(addoefiles):
259                                         if not files.count(aof):
260                                                 if not os.path.isabs(aof):
261                                                         aof = os.path.join(os.path.dirname(f),aof)
262                                                 files.append(aof)
263                         for var in pkgdata[f].keys():
264                                 if data.getVarFlag(var, "handler", pkgdata[f]) and data.getVar(var, pkgdata[f]):
265                                         event.register(data.getVar(var, pkgdata[f]))
266                         depstr = data.getVar("DEPENDS", pkgdata[f], 1)
267                         if depstr is not None:
268                                 deps = depstr.split()
269                         pkg = []
270                         pkg.append(data.getVar('CATEGORY', pkgdata[f], 1))
271                         pkg.append(data.getVar('PN', pkgdata[f], 1))
272                         pkg.append(data.getVar('PV', pkgdata[f], 1))
273                         pkg.append(data.getVar('PR', pkgdata[f], 1))
274                         root = "%s/%s-%s-%s" % (pkg[0], pkg[1], pkg[2], pkg[3])
275                         provides = []
276                         # w/ category
277                         provides.append("%s/%s-%s" % (pkg[0], pkg[1], pkg[2]))
278                         provides.append("%s/%s" % (pkg[0], pkg[1]))
279                         # w/o category
280                         provides.append("%s" % pkg[1])
281                         provides.append("%s-%s" % (pkg[1], pkg[2]))
282                         provides.append("%s-%s-%s" % (pkg[1], pkg[2], pkg[3]))
283                         providestr = data.getVar("PROVIDES", pkgdata[f], 1)
284                         if providestr is not None:
285                                 provides += providestr.split()
286                         for provide in provides:
287                                 pkgs[provide] = [[root], None]
288                         pkgs[root] = [deps, f]
289         except IOError:
290                 print "error opening %s" % f
291                 pass
292
293 # add every provide relationship to the dependency graph, depending
294 # on all the packages that provide it
295
296 global __tokill
297 global __unsatisfied
298 __tokill = []
299 __unsatisfied = []
300
301 for pkg in pkgs.keys():
302         graph.addnode(pkg, None)
303
304 for pkg in pkgs.keys():
305         (deps, fn) = pkgs[pkg]
306         if depcmd is not None:
307                 if deps is not None:
308                         for d in deps:
309                                 if not graph.hasnode(d):
310                                         def killitem(graph, item):
311                                                 global __tokill
312                                                 __tokill.append(item)
313                                         graph.walkup(pkg, killitem)
314                                         __unsatisfied.append([pkg, d])
315                                         break
316                                 graph.addnode(pkg, d)
317
318 for u in __unsatisfied:
319         event.fire(UnsatisfiedDep(u[0], pkgdata[pkgs[u[0]][1]], u[1]))
320
321 for k in __tokill:
322         def reallykillitem(graph, item):
323                 graph.delnode(item)
324         graph.walkup(k, reallykillitem)
325
326 event.fire(BuildStarted(buildname, graph.okeys, cfg))
327 packages = args or graph.okeys
328
329 for k in packages:
330         if pkgs.has_key(k):
331                 ret = graph.walkdown(k, build)
332                 if abort and not ret:
333                         oe.fatal("Build of %s failed, aborting." % k)
334         else:
335                 oe.error("Unable to build %s: no .oe file provides it." % k)
336                 if abort:
337                         sys.exit(1)
338
339 event.fire(BuildCompleted(buildname, graph.okeys, cfg))