diff options
Diffstat (limited to 'bitbake/lib/bb/build.py')
-rw-r--r-- | bitbake/lib/bb/build.py | 226 |
1 files changed, 118 insertions, 108 deletions
diff --git a/bitbake/lib/bb/build.py b/bitbake/lib/bb/build.py index 1d6742b6e6..6d80b4b549 100644 --- a/bitbake/lib/bb/build.py +++ b/bitbake/lib/bb/build.py | |||
@@ -25,8 +25,8 @@ | |||
25 | # | 25 | # |
26 | #Based on functions from the base bb module, Copyright 2003 Holger Schurig | 26 | #Based on functions from the base bb module, Copyright 2003 Holger Schurig |
27 | 27 | ||
28 | from bb import data, fetch, event, mkdirhier, utils | 28 | from bb import data, event, mkdirhier, utils |
29 | import bb, os | 29 | import bb, os, sys |
30 | 30 | ||
31 | # When we execute a python function we'd like certain things | 31 | # When we execute a python function we'd like certain things |
32 | # in all namespaces, hence we add them to __builtins__ | 32 | # in all namespaces, hence we add them to __builtins__ |
@@ -37,7 +37,11 @@ __builtins__['os'] = os | |||
37 | 37 | ||
38 | # events | 38 | # events |
39 | class FuncFailed(Exception): | 39 | class FuncFailed(Exception): |
40 | """Executed function failed""" | 40 | """ |
41 | Executed function failed | ||
42 | First parameter a message | ||
43 | Second paramter is a logfile (optional) | ||
44 | """ | ||
41 | 45 | ||
42 | class EventException(Exception): | 46 | class EventException(Exception): |
43 | """Exception which is associated with an Event.""" | 47 | """Exception which is associated with an Event.""" |
@@ -50,7 +54,9 @@ class TaskBase(event.Event): | |||
50 | 54 | ||
51 | def __init__(self, t, d ): | 55 | def __init__(self, t, d ): |
52 | self._task = t | 56 | self._task = t |
53 | event.Event.__init__(self, d) | 57 | self._package = bb.data.getVar("PF", d, 1) |
58 | event.Event.__init__(self) | ||
59 | self._message = "package %s: task %s: %s" % (bb.data.getVar("PF", d, 1), t, bb.event.getName(self)[4:]) | ||
54 | 60 | ||
55 | def getTask(self): | 61 | def getTask(self): |
56 | return self._task | 62 | return self._task |
@@ -68,6 +74,10 @@ class TaskSucceeded(TaskBase): | |||
68 | 74 | ||
69 | class TaskFailed(TaskBase): | 75 | class TaskFailed(TaskBase): |
70 | """Task execution failed""" | 76 | """Task execution failed""" |
77 | def __init__(self, msg, logfile, t, d ): | ||
78 | self.logfile = logfile | ||
79 | self.msg = msg | ||
80 | TaskBase.__init__(self, t, d) | ||
71 | 81 | ||
72 | class InvalidTask(TaskBase): | 82 | class InvalidTask(TaskBase): |
73 | """Invalid Task""" | 83 | """Invalid Task""" |
@@ -104,42 +114,116 @@ def exec_func(func, d, dirs = None): | |||
104 | else: | 114 | else: |
105 | adir = data.getVar('B', d, 1) | 115 | adir = data.getVar('B', d, 1) |
106 | 116 | ||
117 | # Save current directory | ||
107 | try: | 118 | try: |
108 | prevdir = os.getcwd() | 119 | prevdir = os.getcwd() |
109 | except OSError: | 120 | except OSError: |
110 | prevdir = data.getVar('TOPDIR', d, True) | 121 | prevdir = data.getVar('TOPDIR', d, True) |
122 | |||
123 | # Setup logfiles | ||
124 | t = data.getVar('T', d, 1) | ||
125 | if not t: | ||
126 | bb.msg.fatal(bb.msg.domain.Build, "T not set") | ||
127 | mkdirhier(t) | ||
128 | # Gross hack, FIXME | ||
129 | import random | ||
130 | logfile = "%s/log.%s.%s.%s" % (t, func, str(os.getpid()),random.random()) | ||
131 | runfile = "%s/run.%s.%s" % (t, func, str(os.getpid())) | ||
132 | |||
133 | # Change to correct directory (if specified) | ||
111 | if adir and os.access(adir, os.F_OK): | 134 | if adir and os.access(adir, os.F_OK): |
112 | os.chdir(adir) | 135 | os.chdir(adir) |
113 | 136 | ||
137 | # Handle logfiles | ||
138 | si = file('/dev/null', 'r') | ||
139 | try: | ||
140 | if bb.msg.debug_level['default'] > 0 or ispython: | ||
141 | so = os.popen("tee \"%s\"" % logfile, "w") | ||
142 | else: | ||
143 | so = file(logfile, 'w') | ||
144 | except OSError, e: | ||
145 | bb.msg.error(bb.msg.domain.Build, "opening log file: %s" % e) | ||
146 | pass | ||
147 | |||
148 | se = so | ||
149 | |||
150 | # Dup the existing fds so we dont lose them | ||
151 | osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()] | ||
152 | oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()] | ||
153 | ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()] | ||
154 | |||
155 | # Replace those fds with our own | ||
156 | os.dup2(si.fileno(), osi[1]) | ||
157 | os.dup2(so.fileno(), oso[1]) | ||
158 | os.dup2(se.fileno(), ose[1]) | ||
159 | |||
114 | locks = [] | 160 | locks = [] |
115 | lockfiles = (data.expand(flags['lockfiles'], d) or "").split() | 161 | lockfiles = (data.expand(flags['lockfiles'], d) or "").split() |
116 | for lock in lockfiles: | 162 | for lock in lockfiles: |
117 | locks.append(bb.utils.lockfile(lock)) | 163 | locks.append(bb.utils.lockfile(lock)) |
118 | 164 | ||
119 | if flags['python']: | 165 | try: |
120 | exec_func_python(func, d) | 166 | # Run the function |
121 | else: | 167 | if ispython: |
122 | exec_func_shell(func, d, flags) | 168 | exec_func_python(func, d, runfile, logfile) |
169 | else: | ||
170 | exec_func_shell(func, d, runfile, logfile, flags) | ||
171 | |||
172 | # Restore original directory | ||
173 | try: | ||
174 | os.chdir(prevdir) | ||
175 | except: | ||
176 | pass | ||
123 | 177 | ||
124 | for lock in locks: | 178 | finally: |
125 | bb.utils.unlockfile(lock) | ||
126 | 179 | ||
127 | if os.path.exists(prevdir): | 180 | # Unlock any lockfiles |
128 | os.chdir(prevdir) | 181 | for lock in locks: |
182 | bb.utils.unlockfile(lock) | ||
183 | |||
184 | # Restore the backup fds | ||
185 | os.dup2(osi[0], osi[1]) | ||
186 | os.dup2(oso[0], oso[1]) | ||
187 | os.dup2(ose[0], ose[1]) | ||
188 | |||
189 | # Close our logs | ||
190 | si.close() | ||
191 | so.close() | ||
192 | se.close() | ||
129 | 193 | ||
130 | def exec_func_python(func, d): | 194 | if os.path.exists(logfile) and os.path.getsize(logfile) == 0: |
195 | bb.msg.debug(2, bb.msg.domain.Build, "Zero size logfile %s, removing" % logfile) | ||
196 | os.remove(logfile) | ||
197 | |||
198 | # Close the backup fds | ||
199 | os.close(osi[0]) | ||
200 | os.close(oso[0]) | ||
201 | os.close(ose[0]) | ||
202 | |||
203 | def exec_func_python(func, d, runfile, logfile): | ||
131 | """Execute a python BB 'function'""" | 204 | """Execute a python BB 'function'""" |
132 | import re | 205 | import re, os |
133 | 206 | ||
134 | bbfile = bb.data.getVar('FILE', d, 1) | 207 | bbfile = bb.data.getVar('FILE', d, 1) |
135 | tmp = "def " + func + "():\n%s" % data.getVar(func, d) | 208 | tmp = "def " + func + "():\n%s" % data.getVar(func, d) |
136 | tmp += '\n' + func + '()' | 209 | tmp += '\n' + func + '()' |
210 | |||
211 | f = open(runfile, "w") | ||
212 | f.write(tmp) | ||
137 | comp = utils.better_compile(tmp, func, bbfile) | 213 | comp = utils.better_compile(tmp, func, bbfile) |
138 | g = {} # globals | 214 | g = {} # globals |
139 | g['d'] = d | 215 | g['d'] = d |
140 | utils.better_exec(comp, g, tmp, bbfile) | 216 | try: |
217 | utils.better_exec(comp, g, tmp, bbfile) | ||
218 | except: | ||
219 | (t,value,tb) = sys.exc_info() | ||
220 | |||
221 | if t in [bb.parse.SkipPackage, bb.build.FuncFailed]: | ||
222 | raise | ||
223 | bb.msg.error(bb.msg.domain.Build, "Function %s failed" % func) | ||
224 | raise FuncFailed("function %s failed" % func, logfile) | ||
141 | 225 | ||
142 | def exec_func_shell(func, d, flags): | 226 | def exec_func_shell(func, d, runfile, logfile, flags): |
143 | """Execute a shell BB 'function' Returns true if execution was successful. | 227 | """Execute a shell BB 'function' Returns true if execution was successful. |
144 | 228 | ||
145 | For this, it creates a bash shell script in the tmp dectory, writes the local | 229 | For this, it creates a bash shell script in the tmp dectory, writes the local |
@@ -149,23 +233,13 @@ def exec_func_shell(func, d, flags): | |||
149 | of the directories you need created prior to execution. The last | 233 | of the directories you need created prior to execution. The last |
150 | item in the list is where we will chdir/cd to. | 234 | item in the list is where we will chdir/cd to. |
151 | """ | 235 | """ |
152 | import sys | ||
153 | 236 | ||
154 | deps = flags['deps'] | 237 | deps = flags['deps'] |
155 | check = flags['check'] | 238 | check = flags['check'] |
156 | interact = flags['interactive'] | ||
157 | if check in globals(): | 239 | if check in globals(): |
158 | if globals()[check](func, deps): | 240 | if globals()[check](func, deps): |
159 | return | 241 | return |
160 | 242 | ||
161 | global logfile | ||
162 | t = data.getVar('T', d, 1) | ||
163 | if not t: | ||
164 | return 0 | ||
165 | mkdirhier(t) | ||
166 | logfile = "%s/log.%s.%s" % (t, func, str(os.getpid())) | ||
167 | runfile = "%s/run.%s.%s" % (t, func, str(os.getpid())) | ||
168 | |||
169 | f = open(runfile, "w") | 243 | f = open(runfile, "w") |
170 | f.write("#!/bin/sh -e\n") | 244 | f.write("#!/bin/sh -e\n") |
171 | if bb.msg.debug_level['default'] > 0: f.write("set -x\n") | 245 | if bb.msg.debug_level['default'] > 0: f.write("set -x\n") |
@@ -177,91 +251,21 @@ def exec_func_shell(func, d, flags): | |||
177 | os.chmod(runfile, 0775) | 251 | os.chmod(runfile, 0775) |
178 | if not func: | 252 | if not func: |
179 | bb.msg.error(bb.msg.domain.Build, "Function not specified") | 253 | bb.msg.error(bb.msg.domain.Build, "Function not specified") |
180 | raise FuncFailed() | 254 | raise FuncFailed("Function not specified for exec_func_shell") |
181 | |||
182 | # open logs | ||
183 | si = file('/dev/null', 'r') | ||
184 | try: | ||
185 | if bb.msg.debug_level['default'] > 0: | ||
186 | so = os.popen("tee \"%s\"" % logfile, "w") | ||
187 | else: | ||
188 | so = file(logfile, 'w') | ||
189 | except OSError, e: | ||
190 | bb.msg.error(bb.msg.domain.Build, "opening log file: %s" % e) | ||
191 | pass | ||
192 | |||
193 | se = so | ||
194 | |||
195 | if not interact: | ||
196 | # dup the existing fds so we dont lose them | ||
197 | osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()] | ||
198 | oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()] | ||
199 | ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()] | ||
200 | |||
201 | # replace those fds with our own | ||
202 | os.dup2(si.fileno(), osi[1]) | ||
203 | os.dup2(so.fileno(), oso[1]) | ||
204 | os.dup2(se.fileno(), ose[1]) | ||
205 | 255 | ||
206 | # execute function | 256 | # execute function |
207 | prevdir = os.getcwd() | ||
208 | if flags['fakeroot']: | 257 | if flags['fakeroot']: |
209 | maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1) | 258 | maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1) |
210 | else: | 259 | else: |
211 | maybe_fakeroot = '' | 260 | maybe_fakeroot = '' |
212 | lang_environment = "LC_ALL=C " | 261 | lang_environment = "LC_ALL=C " |
213 | ret = os.system('%s%ssh -e %s' % (lang_environment, maybe_fakeroot, runfile)) | 262 | ret = os.system('%s%ssh -e %s' % (lang_environment, maybe_fakeroot, runfile)) |
214 | try: | ||
215 | os.chdir(prevdir) | ||
216 | except: | ||
217 | pass | ||
218 | |||
219 | if not interact: | ||
220 | # restore the backups | ||
221 | os.dup2(osi[0], osi[1]) | ||
222 | os.dup2(oso[0], oso[1]) | ||
223 | os.dup2(ose[0], ose[1]) | ||
224 | 263 | ||
225 | # close our logs | 264 | if ret == 0: |
226 | si.close() | ||
227 | so.close() | ||
228 | se.close() | ||
229 | |||
230 | if os.path.exists(logfile) and os.path.getsize(logfile) == 0: | ||
231 | bb.msg.debug(2, bb.msg.domain.Build, "Zero size logfile %s, removing" % logfile) | ||
232 | os.remove(logfile) | ||
233 | |||
234 | # close the backup fds | ||
235 | os.close(osi[0]) | ||
236 | os.close(oso[0]) | ||
237 | os.close(ose[0]) | ||
238 | |||
239 | if ret==0: | ||
240 | if bb.msg.debug_level['default'] > 0: | ||
241 | os.remove(runfile) | ||
242 | # os.remove(logfile) | ||
243 | return | 265 | return |
244 | else: | 266 | |
245 | bb.msg.error(bb.msg.domain.Build, "function %s failed" % func) | 267 | bb.msg.error(bb.msg.domain.Build, "Function %s failed" % func) |
246 | if data.getVar("BBINCLUDELOGS", d): | 268 | raise FuncFailed("function %s failed" % func, logfile) |
247 | bb.msg.error(bb.msg.domain.Build, "log data follows (%s)" % logfile) | ||
248 | number_of_lines = data.getVar("BBINCLUDELOGS_LINES", d) | ||
249 | if number_of_lines: | ||
250 | os.system('tail -n%s %s' % (number_of_lines, logfile)) | ||
251 | elif os.path.exists(logfile): | ||
252 | f = open(logfile, "r") | ||
253 | while True: | ||
254 | l = f.readline() | ||
255 | if l == '': | ||
256 | break | ||
257 | l = l.rstrip() | ||
258 | print '| %s' % l | ||
259 | f.close() | ||
260 | else: | ||
261 | bb.msg.error(bb.msg.domain.Build, "There was no logfile output") | ||
262 | else: | ||
263 | bb.msg.error(bb.msg.domain.Build, "see log in %s" % logfile) | ||
264 | raise FuncFailed( logfile ) | ||
265 | 269 | ||
266 | 270 | ||
267 | def exec_task(task, d): | 271 | def exec_task(task, d): |
@@ -282,14 +286,20 @@ def exec_task(task, d): | |||
282 | data.setVar('OVERRIDES', 'task-%s:%s' % (task[3:], old_overrides), localdata) | 286 | data.setVar('OVERRIDES', 'task-%s:%s' % (task[3:], old_overrides), localdata) |
283 | data.update_data(localdata) | 287 | data.update_data(localdata) |
284 | data.expandKeys(localdata) | 288 | data.expandKeys(localdata) |
285 | event.fire(TaskStarted(task, localdata)) | 289 | event.fire(TaskStarted(task, localdata), localdata) |
286 | exec_func(task, localdata) | 290 | exec_func(task, localdata) |
287 | event.fire(TaskSucceeded(task, localdata)) | 291 | event.fire(TaskSucceeded(task, localdata), localdata) |
288 | except FuncFailed, reason: | 292 | except FuncFailed, message: |
289 | bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % reason ) | 293 | # Try to extract the optional logfile |
290 | failedevent = TaskFailed(task, d) | 294 | try: |
291 | event.fire(failedevent) | 295 | (msg, logfile) = message |
292 | raise EventException("Function failed in task: %s" % reason, failedevent) | 296 | except: |
297 | logfile = None | ||
298 | msg = message | ||
299 | bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % message ) | ||
300 | failedevent = TaskFailed(msg, logfile, task, d) | ||
301 | event.fire(failedevent, d) | ||
302 | raise EventException("Function failed in task: %s" % message, failedevent) | ||
293 | 303 | ||
294 | # make stamp, or cause event and raise exception | 304 | # make stamp, or cause event and raise exception |
295 | if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d): | 305 | if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d): |