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): |
