summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@linux.intel.com>2010-08-16 16:37:29 +0100
committerRichard Purdie <rpurdie@linux.intel.com>2010-08-19 22:36:25 +0100
commitb6bfe1420517aa5aa190e17dca40ea70f09effd9 (patch)
tree2591a26f18290e8d929517df71f24645394c57fb
parenta45e1d54e19d4cd728e90df929b212e41ef70d4b (diff)
downloadpoky-b6bfe1420517aa5aa190e17dca40ea70f09effd9.tar.gz
bitbake: Switch to use subprocess for forking tasks and FAKEROOTENV to run shell and python under a fakeroot environment
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
-rwxr-xr-xbitbake/bin/bitbake-runtask77
-rw-r--r--bitbake/lib/bb/build.py64
-rw-r--r--bitbake/lib/bb/cooker.py7
-rw-r--r--bitbake/lib/bb/data.py9
-rw-r--r--bitbake/lib/bb/event.py11
-rw-r--r--bitbake/lib/bb/msg.py11
-rw-r--r--bitbake/lib/bb/runqueue.py134
7 files changed, 201 insertions, 112 deletions
diff --git a/bitbake/bin/bitbake-runtask b/bitbake/bin/bitbake-runtask
new file mode 100755
index 0000000000..417f3949cd
--- /dev/null
+++ b/bitbake/bin/bitbake-runtask
@@ -0,0 +1,77 @@
1#!/usr/bin/env python
2
3import os
4import sys
5import warnings
6sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
7
8class BBConfiguration(object):
9 """
10 Manages build options and configurations for one run
11 """
12
13 def __init__(self):
14 setattr(self, "data", {})
15 setattr(self, "file", [])
16 setattr(self, "cmd", None)
17
18_warnings_showwarning = warnings.showwarning
19def _showwarning(message, category, filename, lineno, file=None, line=None):
20 """Display python warning messages using bb.msg"""
21 if file is not None:
22 if _warnings_showwarning is not None:
23 _warnings_showwarning(message, category, filename, lineno, file, line)
24 else:
25 s = warnings.formatwarning(message, category, filename, lineno)
26 s = s.split("\n")[0]
27 bb.msg.warn(None, s)
28
29warnings.showwarning = _showwarning
30warnings.simplefilter("ignore", DeprecationWarning)
31
32import bb.event
33
34# Need to map our I/O correctly. Currently stdout is a pipe to
35# the server expecting events. We save this and map stdout to stderr.
36
37eventfd = os.dup(sys.stdout.fileno())
38bb.event.worker_pipe = os.fdopen(eventfd, 'w', 0)
39# Replace those fds with our own
40os.dup2(sys.stderr.fileno(), sys.stdout.fileno())
41
42# Save out the PID so that the event can include it the
43# events
44bb.event.worker_pid = os.getpid()
45bb.event.usestdout = False
46
47
48import bb.cooker
49
50cooker = bb.cooker.BBCooker(BBConfiguration(), None)
51buildfile = sys.argv[1]
52taskname = sys.argv[2]
53
54cooker.parseConfiguration()
55
56cooker.bb_cache = bb.cache.init(cooker)
57cooker.status = bb.cache.CacheData()
58
59(fn, cls) = cooker.bb_cache.virtualfn2realfn(buildfile)
60buildfile = cooker.matchFile(fn)
61fn = cooker.bb_cache.realfn2virtual(buildfile, cls)
62
63cooker.buildSetVars()
64
65# Load data into the cache for fn and parse the loaded cache data
66the_data = cooker.bb_cache.loadDataFull(fn, cooker.get_file_appends(fn), cooker.configuration.data)
67cooker.bb_cache.setData(fn, buildfile, the_data)
68cooker.bb_cache.handle_data(fn, cooker.status)
69
70if taskname.endswith("_setscene"):
71 the_data.setVarFlag(taskname, "quieterrors", "1")
72
73ret = 0
74if sys.argv[3] != "True":
75 ret = bb.build.exec_task(taskname, the_data)
76sys.exit(ret)
77
diff --git a/bitbake/lib/bb/build.py b/bitbake/lib/bb/build.py
index 0bf0154cb4..77af92abee 100644
--- a/bitbake/lib/bb/build.py
+++ b/bitbake/lib/bb/build.py
@@ -44,12 +44,6 @@ class FuncFailed(Exception):
44 Second paramter is a logfile (optional) 44 Second paramter is a logfile (optional)
45 """ 45 """
46 46
47class EventException(Exception):
48 """Exception which is associated with an Event."""
49
50 def __init__(self, msg, event):
51 self.args = msg, event
52
53class TaskBase(event.Event): 47class TaskBase(event.Event):
54 """Base class for task events""" 48 """Base class for task events"""
55 49
@@ -80,7 +74,7 @@ class TaskFailed(TaskBase):
80 self.msg = msg 74 self.msg = msg
81 TaskBase.__init__(self, t, d) 75 TaskBase.__init__(self, t, d)
82 76
83class InvalidTask(TaskBase): 77class TaskInvalid(TaskBase):
84 """Invalid Task""" 78 """Invalid Task"""
85 79
86# functions 80# functions
@@ -94,7 +88,7 @@ def exec_func(func, d, dirs = None):
94 return 88 return
95 89
96 flags = data.getVarFlags(func, d) 90 flags = data.getVarFlags(func, d)
97 for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot']: 91 for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot', 'task']:
98 if not item in flags: 92 if not item in flags:
99 flags[item] = None 93 flags[item] = None
100 94
@@ -138,7 +132,7 @@ def exec_func(func, d, dirs = None):
138 # Handle logfiles 132 # Handle logfiles
139 si = file('/dev/null', 'r') 133 si = file('/dev/null', 'r')
140 try: 134 try:
141 if bb.msg.debug_level['default'] > 0 or ispython: 135 if bb.msg.debug_level['default'] > 0 and not ispython:
142 so = os.popen("tee \"%s\"" % logfile, "w") 136 so = os.popen("tee \"%s\"" % logfile, "w")
143 else: 137 else:
144 so = file(logfile, 'w') 138 so = file(logfile, 'w')
@@ -158,6 +152,8 @@ def exec_func(func, d, dirs = None):
158 os.dup2(so.fileno(), oso[1]) 152 os.dup2(so.fileno(), oso[1])
159 os.dup2(se.fileno(), ose[1]) 153 os.dup2(se.fileno(), ose[1])
160 154
155 bb.event.useStdout = True
156
161 locks = [] 157 locks = []
162 lockfiles = flags['lockfiles'] 158 lockfiles = flags['lockfiles']
163 if lockfiles: 159 if lockfiles:
@@ -183,6 +179,8 @@ def exec_func(func, d, dirs = None):
183 for lock in locks: 179 for lock in locks:
184 bb.utils.unlockfile(lock) 180 bb.utils.unlockfile(lock)
185 181
182 bb.event.useStdout = False
183
186 # Restore the backup fds 184 # Restore the backup fds
187 os.dup2(osi[0], osi[1]) 185 os.dup2(osi[0], osi[1])
188 os.dup2(oso[0], oso[1]) 186 os.dup2(oso[0], oso[1])
@@ -221,6 +219,7 @@ def exec_func_python(func, d, runfile, logfile):
221 raise 219 raise
222 raise FuncFailed("Function %s failed" % func, logfile) 220 raise FuncFailed("Function %s failed" % func, logfile)
223 221
222
224def exec_func_shell(func, d, runfile, logfile, flags): 223def exec_func_shell(func, d, runfile, logfile, flags):
225 """Execute a shell BB 'function' Returns true if execution was successful. 224 """Execute a shell BB 'function' Returns true if execution was successful.
226 225
@@ -251,12 +250,11 @@ def exec_func_shell(func, d, runfile, logfile, flags):
251 raise FuncFailed("Function not specified for exec_func_shell") 250 raise FuncFailed("Function not specified for exec_func_shell")
252 251
253 # execute function 252 # execute function
254 if flags['fakeroot']: 253 if flags['fakeroot'] and not flags['task']:
255 maybe_fakeroot = "PATH=\"%s\" %s " % (bb.data.getVar("PATH", d, 1), bb.data.getVar("FAKEROOT", d, 1) or "fakeroot") 254 bb.fatal("Function %s specifies fakeroot but isn't a task?!" % func)
256 else: 255
257 maybe_fakeroot = ''
258 lang_environment = "LC_ALL=C " 256 lang_environment = "LC_ALL=C "
259 ret = os.system('%s%ssh -e %s' % (lang_environment, maybe_fakeroot, runfile)) 257 ret = os.system('%ssh -e %s' % (lang_environment, runfile))
260 258
261 if ret == 0: 259 if ret == 0:
262 return 260 return
@@ -273,7 +271,13 @@ def exec_task(task, d):
273 271
274 # Check whther this is a valid task 272 # Check whther this is a valid task
275 if not data.getVarFlag(task, 'task', d): 273 if not data.getVarFlag(task, 'task', d):
276 raise EventException("No such task", InvalidTask(task, d)) 274 event.fire(TaskInvalid(task, d), d)
275 bb.msg.error(bb.msg.domain.Build, "No such task: %s" % task)
276 return 1
277
278 quieterr = False
279 if d.getVarFlag(task, "quieterrors") is not None:
280 quieterr = True
277 281
278 try: 282 try:
279 bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task) 283 bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task)
@@ -292,6 +296,11 @@ def exec_task(task, d):
292 for func in postfuncs: 296 for func in postfuncs:
293 exec_func(func, localdata) 297 exec_func(func, localdata)
294 event.fire(TaskSucceeded(task, localdata), localdata) 298 event.fire(TaskSucceeded(task, localdata), localdata)
299
300 # make stamp, or cause event and raise exception
301 if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d):
302 make_stamp(task, d)
303
295 except FuncFailed as message: 304 except FuncFailed as message:
296 # Try to extract the optional logfile 305 # Try to extract the optional logfile
297 try: 306 try:
@@ -299,14 +308,22 @@ def exec_task(task, d):
299 except: 308 except:
300 logfile = None 309 logfile = None
301 msg = message 310 msg = message
302 bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % message ) 311 if not quieterr:
303 failedevent = TaskFailed(msg, logfile, task, d) 312 bb.msg.error(bb.msg.domain.Build, "Task failed: %s" % message )
304 event.fire(failedevent, d) 313 failedevent = TaskFailed(msg, logfile, task, d)
305 raise EventException("Function failed in task: %s" % message, failedevent) 314 event.fire(failedevent, d)
306 315 return 1
307 # make stamp, or cause event and raise exception 316
308 if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d): 317 except Exception:
309 make_stamp(task, d) 318 from traceback import format_exc
319 if not quieterr:
320 bb.msg.error(bb.msg.domain.Build, "Build of %s failed" % (task))
321 bb.msg.error(bb.msg.domain.Build, format_exc())
322 failedevent = TaskFailed("Task Failed", None, task, d)
323 event.fire(failedevent, d)
324 return 1
325
326 return 0
310 327
311def extract_stamp(d, fn): 328def extract_stamp(d, fn):
312 """ 329 """
@@ -380,6 +397,7 @@ def add_tasks(tasklist, d):
380 getTask('rdeptask') 397 getTask('rdeptask')
381 getTask('recrdeptask') 398 getTask('recrdeptask')
382 getTask('nostamp') 399 getTask('nostamp')
400 getTask('fakeroot')
383 task_deps['parents'][task] = [] 401 task_deps['parents'][task] = []
384 for dep in flags['deps']: 402 for dep in flags['deps']:
385 dep = data.expand(dep, d) 403 dep = data.expand(dep, d)
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index a1620b0162..3a25956625 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -70,12 +70,16 @@ class BBCooker:
70 self.cache = None 70 self.cache = None
71 self.bb_cache = None 71 self.bb_cache = None
72 72
73 self.server = server.BitBakeServer(self) 73 if server:
74 self.server = server.BitBakeServer(self)
74 75
75 self.configuration = configuration 76 self.configuration = configuration
76 77
77 self.configuration.data = bb.data.init() 78 self.configuration.data = bb.data.init()
78 79
80 if not server:
81 bb.data.setVar("BB_WORKERCONTEXT", "1", self.configuration.data)
82
79 bb.data.inheritFromOS(self.configuration.data) 83 bb.data.inheritFromOS(self.configuration.data)
80 84
81 self.parseConfigurationFiles(self.configuration.file) 85 self.parseConfigurationFiles(self.configuration.file)
@@ -544,7 +548,6 @@ class BBCooker:
544 548
545 bb.event.fire(bb.event.ConfigParsed(), self.configuration.data) 549 bb.event.fire(bb.event.ConfigParsed(), self.configuration.data)
546 550
547
548 except IOError as e: 551 except IOError as e:
549 bb.msg.fatal(bb.msg.domain.Parsing, "Error when parsing %s: %s" % (files, str(e))) 552 bb.msg.fatal(bb.msg.domain.Parsing, "Error when parsing %s: %s" % (files, str(e)))
550 except bb.parse.ParseError as details: 553 except bb.parse.ParseError as details:
diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py
index 636983edcc..9e37f5e32d 100644
--- a/bitbake/lib/bb/data.py
+++ b/bitbake/lib/bb/data.py
@@ -229,6 +229,15 @@ def emit_env(o=sys.__stdout__, d = init(), all=False):
229 for key in keys: 229 for key in keys:
230 emit_var(key, o, d, all and not isfunc) and o.write('\n') 230 emit_var(key, o, d, all and not isfunc) and o.write('\n')
231 231
232def export_vars(d):
233 keys = (key for key in d.keys() if d.getVarFlag(key, "export"))
234 ret = {}
235 for k in keys:
236 v = d.getVar(k, True)
237 if v:
238 ret[k] = v
239 return ret
240
232def update_data(d): 241def update_data(d):
233 """Performs final steps upon the datastore, including application of overrides""" 242 """Performs final steps upon the datastore, including application of overrides"""
234 d.finalize() 243 d.finalize()
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py
index 7731649eff..f5ba6eab3c 100644
--- a/bitbake/lib/bb/event.py
+++ b/bitbake/lib/bb/event.py
@@ -31,6 +31,7 @@ import pickle
31# the runqueue forks off. 31# the runqueue forks off.
32worker_pid = 0 32worker_pid = 0
33worker_pipe = None 33worker_pipe = None
34useStdout = True
34 35
35class Event: 36class Event:
36 """Base class for events""" 37 """Base class for events"""
@@ -102,15 +103,12 @@ def fire(event, d):
102 103
103def worker_fire(event, d): 104def worker_fire(event, d):
104 data = "<event>" + pickle.dumps(event) + "</event>" 105 data = "<event>" + pickle.dumps(event) + "</event>"
105 try: 106 worker_pipe.write(data)
106 if os.write(worker_pipe, data) != len (data): 107 worker_pipe.flush()
107 print("Error sending event to server (short write)")
108 except OSError:
109 sys.exit(1)
110 108
111def fire_from_worker(event, d): 109def fire_from_worker(event, d):
112 if not event.startswith("<event>") or not event.endswith("</event>"): 110 if not event.startswith("<event>") or not event.endswith("</event>"):
113 print("Error, not an event") 111 print("Error, not an event %s" % event)
114 return 112 return
115 event = pickle.loads(event[7:-8]) 113 event = pickle.loads(event[7:-8])
116 fire_ui_handlers(event, d) 114 fire_ui_handlers(event, d)
@@ -140,6 +138,7 @@ def remove(name, handler):
140def register_UIHhandler(handler): 138def register_UIHhandler(handler):
141 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 139 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
142 _ui_handlers[_ui_handler_seq] = handler 140 _ui_handlers[_ui_handler_seq] = handler
141 bb.event.useStdout = False
143 return _ui_handler_seq 142 return _ui_handler_seq
144 143
145def unregister_UIHhandler(handlerNum): 144def unregister_UIHhandler(handlerNum):
diff --git a/bitbake/lib/bb/msg.py b/bitbake/lib/bb/msg.py
index 8d2bcce452..5bb30e8dd3 100644
--- a/bitbake/lib/bb/msg.py
+++ b/bitbake/lib/bb/msg.py
@@ -109,7 +109,7 @@ def debug(level, msgdomain, msg, fn = None):
109 109
110 if debug_level[msgdomain] >= level: 110 if debug_level[msgdomain] >= level:
111 bb.event.fire(MsgDebug(msg), None) 111 bb.event.fire(MsgDebug(msg), None)
112 if not bb.event._ui_handlers: 112 if bb.event.useStdout:
113 print('DEBUG: %s' % (msg)) 113 print('DEBUG: %s' % (msg))
114 114
115def note(level, msgdomain, msg, fn = None): 115def note(level, msgdomain, msg, fn = None):
@@ -118,17 +118,18 @@ def note(level, msgdomain, msg, fn = None):
118 118
119 if level == 1 or verbose or debug_level[msgdomain] >= 1: 119 if level == 1 or verbose or debug_level[msgdomain] >= 1:
120 bb.event.fire(MsgNote(msg), None) 120 bb.event.fire(MsgNote(msg), None)
121 if not bb.event._ui_handlers: 121 if bb.event.useStdout:
122 print('NOTE: %s' % (msg)) 122 print('NOTE: %s' % (msg))
123 123
124def warn(msgdomain, msg, fn = None): 124def warn(msgdomain, msg, fn = None):
125 bb.event.fire(MsgWarn(msg), None) 125 bb.event.fire(MsgWarn(msg), None)
126 if not bb.event._ui_handlers: 126 if bb.event.useStdout:
127 print('WARNING: %s' % (msg)) 127 print('WARNING: %s' % (msg))
128 128
129def error(msgdomain, msg, fn = None): 129def error(msgdomain, msg, fn = None):
130 bb.event.fire(MsgError(msg), None) 130 bb.event.fire(MsgError(msg), None)
131 print('ERROR: %s' % (msg)) 131 if bb.event.useStdout:
132 print('ERROR: %s' % (msg))
132 133
133def fatal(msgdomain, msg, fn = None): 134def fatal(msgdomain, msg, fn = None):
134 bb.event.fire(MsgFatal(msg), None) 135 bb.event.fire(MsgFatal(msg), None)
@@ -137,5 +138,5 @@ def fatal(msgdomain, msg, fn = None):
137 138
138def plain(msg, fn = None): 139def plain(msg, fn = None):
139 bb.event.fire(MsgPlain(msg), None) 140 bb.event.fire(MsgPlain(msg), None)
140 if not bb.event._ui_handlers: 141 if bb.event.useStdout:
141 print(msg) 142 print(msg)
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py
index 9127f248d5..b2d5fc01ab 100644
--- a/bitbake/lib/bb/runqueue.py
+++ b/bitbake/lib/bb/runqueue.py
@@ -23,6 +23,7 @@ Handles preparation and execution of a queue of tasks
23# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 24
25import bb, os, sys 25import bb, os, sys
26import subprocess
26from bb import msg, data, event 27from bb import msg, data, event
27import signal 28import signal
28import stat 29import stat
@@ -937,6 +938,7 @@ class RunQueueExecute:
937 self.runq_complete = [] 938 self.runq_complete = []
938 self.build_pids = {} 939 self.build_pids = {}
939 self.build_pipes = {} 940 self.build_pipes = {}
941 self.build_procs = {}
940 self.failed_fnids = [] 942 self.failed_fnids = []
941 943
942 def runqueue_process_waitpid(self): 944 def runqueue_process_waitpid(self):
@@ -944,19 +946,22 @@ class RunQueueExecute:
944 Return none is there are no processes awaiting result collection, otherwise 946 Return none is there are no processes awaiting result collection, otherwise
945 collect the process exit codes and close the information pipe. 947 collect the process exit codes and close the information pipe.
946 """ 948 """
947 result = os.waitpid(-1, os.WNOHANG) 949 for pid in self.build_procs.keys():
948 if result[0] is 0 and result[1] is 0: 950 proc = self.build_procs[pid]
949 return None 951 proc.poll()
950 task = self.build_pids[result[0]] 952 if proc.returncode is not None:
951 del self.build_pids[result[0]] 953 task = self.build_pids[pid]
952 self.build_pipes[result[0]].close() 954 del self.build_pids[pid]
953 del self.build_pipes[result[0]] 955 self.build_pipes[pid].close()
954 if result[1] != 0: 956 del self.build_pipes[pid]
955 self.task_fail(task, result[1]) 957 del self.build_procs[pid]
956 else: 958 if proc.returncode != 0:
957 self.task_complete(task) 959 self.task_fail(task, proc.returncode)
958 self.stats.taskCompleted() 960 else:
959 bb.event.fire(runQueueTaskCompleted(task, self.stats, self.rq), self.cfgData) 961 self.task_complete(task)
962 self.stats.taskCompleted()
963 bb.event.fire(runQueueTaskCompleted(task, self.stats, self.rq), self.cfgData)
964
960 965
961 def finish_now(self): 966 def finish_now(self):
962 if self.stats.active: 967 if self.stats.active:
@@ -990,31 +995,8 @@ class RunQueueExecute:
990 def fork_off_task(self, fn, task, taskname): 995 def fork_off_task(self, fn, task, taskname):
991 sys.stdout.flush() 996 sys.stdout.flush()
992 sys.stderr.flush() 997 sys.stderr.flush()
993 try:
994 pipein, pipeout = os.pipe()
995 pid = os.fork()
996 except OSError as e:
997 bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror))
998 if pid == 0:
999 os.close(pipein)
1000 # Save out the PID so that the event can include it the
1001 # events
1002 bb.event.worker_pid = os.getpid()
1003 bb.event.worker_pipe = pipeout
1004
1005 self.rq.state = runQueueChildProcess
1006 # Make the child the process group leader
1007 os.setpgid(0, 0)
1008 # No stdin
1009 newsi = os.open('/dev/null', os.O_RDWR)
1010 os.dup2(newsi, sys.stdin.fileno())
1011 # Stdout to a logfile
1012 #logout = data.expand("${TMPDIR}/log/stdout.%s" % os.getpid(), self.cfgData, True)
1013 #mkdirhier(os.path.dirname(logout))
1014 #newso = open(logout, 'w')
1015 #os.dup2(newso.fileno(), sys.stdout.fileno())
1016 #os.dup2(newso.fileno(), sys.stderr.fileno())
1017 998
999 try:
1018 bb.event.fire(runQueueTaskStarted(task, self.stats, self.rq), self.cfgData) 1000 bb.event.fire(runQueueTaskStarted(task, self.stats, self.rq), self.cfgData)
1019 bb.msg.note(1, bb.msg.domain.RunQueue, 1001 bb.msg.note(1, bb.msg.domain.RunQueue,
1020 "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.stats.active + self.stats.failed + 1, 1002 "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.stats.active + self.stats.failed + 1,
@@ -1022,26 +1004,25 @@ class RunQueueExecute:
1022 task, 1004 task,
1023 self.rqdata.get_user_idstring(task))) 1005 self.rqdata.get_user_idstring(task)))
1024 1006
1025 bb.data.setVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", self, self.cooker.configuration.data) 1007 the_data = self.cooker.bb_cache.loadDataFull(fn, self.cooker.get_file_appends(fn), self.cooker.configuration.data)
1026 bb.data.setVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY2", fn, self.cooker.configuration.data) 1008
1027 try: 1009 env = bb.data.export_vars(the_data)
1028 the_data = self.cooker.bb_cache.loadDataFull(fn, self.cooker.get_file_appends(fn), self.cooker.configuration.data) 1010
1029 1011 taskdep = self.rqdata.dataCache.task_deps[fn]
1030 if not self.cooker.configuration.dry_run: 1012 if 'fakeroot' in taskdep and taskname in taskdep['fakeroot']:
1031 bb.build.exec_task(taskname, the_data) 1013 envvars = the_data.getVar("FAKEROOTENV", True).split()
1032 os._exit(0) 1014 for var in envvars:
1033 1015 comps = var.split("=")
1034 except bb.build.EventException as e: 1016 env[comps[0]] = comps[1]
1035 event = e.args[1] 1017
1036 bb.msg.error(bb.msg.domain.Build, "%s event exception, aborting" % bb.event.getName(event)) 1018 proc = subprocess.Popen(["bitbake-runtask", fn, taskname, str(self.cooker.configuration.dry_run)], env=env, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
1037 os._exit(1) 1019 pipein = proc.stdout
1038 except Exception: 1020 pipeout = proc.stdin
1039 from traceback import format_exc 1021 pid = proc.pid
1040 bb.msg.error(bb.msg.domain.Build, "Build of %s %s failed" % (fn, taskname)) 1022 except OSError as e:
1041 bb.msg.error(bb.msg.domain.Build, format_exc()) 1023 bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror))
1042 os._exit(1) 1024
1043 os._exit(0) 1025 return proc
1044 return pid, pipein, pipeout
1045 1026
1046class RunQueueExecuteTasks(RunQueueExecute): 1027class RunQueueExecuteTasks(RunQueueExecute):
1047 def __init__(self, rq): 1028 def __init__(self, rq):
@@ -1153,10 +1134,11 @@ class RunQueueExecuteTasks(RunQueueExecute):
1153 self.task_skip(task) 1134 self.task_skip(task)
1154 continue 1135 continue
1155 1136
1156 pid, pipein, pipeout = self.fork_off_task(fn, task, taskname) 1137 proc = self.fork_off_task(fn, task, taskname)
1157 1138
1158 self.build_pids[pid] = task 1139 self.build_pids[proc.pid] = task
1159 self.build_pipes[pid] = runQueuePipe(pipein, pipeout, self.cfgData) 1140 self.build_procs[proc.pid] = proc
1141 self.build_pipes[proc.pid] = runQueuePipe(proc.stdout, proc.stdin, self.cfgData)
1160 self.runq_running[task] = 1 1142 self.runq_running[task] = 1
1161 self.stats.taskActive() 1143 self.stats.taskActive()
1162 if self.stats.active < self.number_tasks: 1144 if self.stats.active < self.number_tasks:
@@ -1356,10 +1338,11 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
1356 self.task_skip(task) 1338 self.task_skip(task)
1357 return True 1339 return True
1358 1340
1359 pid, pipein, pipeout = self.fork_off_task(fn, realtask, taskname) 1341 proc = self.fork_off_task(fn, realtask, taskname)
1360 1342
1361 self.build_pids[pid] = task 1343 self.build_pids[proc.pid] = task
1362 self.build_pipes[pid] = runQueuePipe(pipein, pipeout, self.cfgData) 1344 self.build_procs[proc.pid] = proc
1345 self.build_pipes[proc.pid] = runQueuePipe(proc.stdout, proc.stdin, self.cfgData)
1363 self.runq_running[task] = 1 1346 self.runq_running[task] = 1
1364 self.stats.taskActive() 1347 self.stats.taskActive()
1365 if self.stats.active < self.number_tasks: 1348 if self.stats.active < self.number_tasks:
@@ -1384,7 +1367,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
1384 self.rq.state = runQueueRunInit 1367 self.rq.state = runQueueRunInit
1385 return True 1368 return True
1386 1369
1387
1388class TaskFailure(Exception): 1370class TaskFailure(Exception):
1389 """ 1371 """
1390 Exception raised when a task in a runqueue fails 1372 Exception raised when a task in a runqueue fails
@@ -1437,14 +1419,14 @@ class runQueueTaskCompleted(runQueueEvent):
1437 runQueueEvent.__init__(self, task, stats, rq) 1419 runQueueEvent.__init__(self, task, stats, rq)
1438 self.message = "Task %s completed (%s)" % (task, self.taskstring) 1420 self.message = "Task %s completed (%s)" % (task, self.taskstring)
1439 1421
1440def check_stamp_fn(fn, taskname, d): 1422#def check_stamp_fn(fn, taskname, d):
1441 rq = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", d) 1423# rq = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", d)
1442 fn = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY2", d) 1424# fn = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY2", d)
1443 fnid = rq.rqdata.taskData.getfn_id(fn) 1425# fnid = rq.rqdata.taskData.getfn_id(fn)
1444 taskid = rq.get_task_id(fnid, taskname) 1426# taskid = rq.get_task_id(fnid, taskname)
1445 if taskid is not None: 1427# if taskid is not None:
1446 return rq.check_stamp_task(taskid) 1428# return rq.check_stamp_task(taskid)
1447 return None 1429# return None
1448 1430
1449class runQueuePipe(): 1431class runQueuePipe():
1450 """ 1432 """
@@ -1452,7 +1434,7 @@ class runQueuePipe():
1452 """ 1434 """
1453 def __init__(self, pipein, pipeout, d): 1435 def __init__(self, pipein, pipeout, d):
1454 self.fd = pipein 1436 self.fd = pipein
1455 os.close(pipeout) 1437 pipeout.close()
1456 fcntl.fcntl(self.fd, fcntl.F_SETFL, fcntl.fcntl(self.fd, fcntl.F_GETFL) | os.O_NONBLOCK) 1438 fcntl.fcntl(self.fd, fcntl.F_SETFL, fcntl.fcntl(self.fd, fcntl.F_GETFL) | os.O_NONBLOCK)
1457 self.queue = "" 1439 self.queue = ""
1458 self.d = d 1440 self.d = d
@@ -1460,8 +1442,8 @@ class runQueuePipe():
1460 def read(self): 1442 def read(self):
1461 start = len(self.queue) 1443 start = len(self.queue)
1462 try: 1444 try:
1463 self.queue = self.queue + os.read(self.fd, 1024) 1445 self.queue = self.queue + self.fd.read(1024)
1464 except OSError: 1446 except IOError:
1465 pass 1447 pass
1466 end = len(self.queue) 1448 end = len(self.queue)
1467 index = self.queue.find("</event>") 1449 index = self.queue.find("</event>")
@@ -1476,4 +1458,4 @@ class runQueuePipe():
1476 continue 1458 continue
1477 if len(self.queue) > 0: 1459 if len(self.queue) > 0:
1478 print("Warning, worker left partial message") 1460 print("Warning, worker left partial message")
1479 os.close(self.fd) 1461 self.fd.close()