mirror of
https://git.yoctoproject.org/poky
synced 2026-02-09 02:03:04 +01:00
Create a fifo under ${T} for each running task that can be used by the
task to send events back to BitBake. The purpose of this is to allow
OpenEmbedded's logging.bbclass (which provides shell function
equivalents for bb.warn(), bb.note() etc.) to have those functions
trigger the appropriate events within BitBake so that messages are shown
through the BitBake UI rather than just in the task log; to do that we
just call the python functions.
Part of the fix for [YOCTO #5275].
(Bitbake rev: bae330a1f8a59a912eca71177b3c6ba7c92a2f38)
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
153 lines
4.2 KiB
Python
153 lines
4.2 KiB
Python
import logging
|
|
import signal
|
|
import subprocess
|
|
import errno
|
|
import select
|
|
|
|
logger = logging.getLogger('BitBake.Process')
|
|
|
|
def subprocess_setup():
|
|
# Python installs a SIGPIPE handler by default. This is usually not what
|
|
# non-Python subprocesses expect.
|
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
|
|
class CmdError(RuntimeError):
|
|
def __init__(self, command, msg=None):
|
|
self.command = command
|
|
self.msg = msg
|
|
|
|
def __str__(self):
|
|
if not isinstance(self.command, basestring):
|
|
cmd = subprocess.list2cmdline(self.command)
|
|
else:
|
|
cmd = self.command
|
|
|
|
msg = "Execution of '%s' failed" % cmd
|
|
if self.msg:
|
|
msg += ': %s' % self.msg
|
|
return msg
|
|
|
|
class NotFoundError(CmdError):
|
|
def __str__(self):
|
|
return CmdError.__str__(self) + ": command not found"
|
|
|
|
class ExecutionError(CmdError):
|
|
def __init__(self, command, exitcode, stdout = None, stderr = None):
|
|
CmdError.__init__(self, command)
|
|
self.exitcode = exitcode
|
|
self.stdout = stdout
|
|
self.stderr = stderr
|
|
|
|
def __str__(self):
|
|
message = ""
|
|
if self.stderr:
|
|
message += self.stderr
|
|
if self.stdout:
|
|
message += self.stdout
|
|
if message:
|
|
message = ":\n" + message
|
|
return (CmdError.__str__(self) +
|
|
" with exit code %s" % self.exitcode + message)
|
|
|
|
class Popen(subprocess.Popen):
|
|
defaults = {
|
|
"close_fds": True,
|
|
"preexec_fn": subprocess_setup,
|
|
"stdout": subprocess.PIPE,
|
|
"stderr": subprocess.STDOUT,
|
|
"stdin": subprocess.PIPE,
|
|
"shell": False,
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
options = dict(self.defaults)
|
|
options.update(kwargs)
|
|
subprocess.Popen.__init__(self, *args, **options)
|
|
|
|
def _logged_communicate(pipe, log, input, extrafiles):
|
|
if pipe.stdin:
|
|
if input is not None:
|
|
pipe.stdin.write(input)
|
|
pipe.stdin.close()
|
|
|
|
outdata, errdata = [], []
|
|
rin = []
|
|
|
|
if pipe.stdout is not None:
|
|
bb.utils.nonblockingfd(pipe.stdout.fileno())
|
|
rin.append(pipe.stdout)
|
|
if pipe.stderr is not None:
|
|
bb.utils.nonblockingfd(pipe.stderr.fileno())
|
|
rin.append(pipe.stderr)
|
|
for fobj, _ in extrafiles:
|
|
bb.utils.nonblockingfd(fobj.fileno())
|
|
rin.append(fobj)
|
|
|
|
def readextras():
|
|
for fobj, func in extrafiles:
|
|
try:
|
|
data = fobj.read()
|
|
except IOError as err:
|
|
if err.errno == errno.EAGAIN or err.errno == errno.EWOULDBLOCK:
|
|
data = None
|
|
if data is not None:
|
|
func(data)
|
|
|
|
try:
|
|
while pipe.poll() is None:
|
|
rlist = rin
|
|
try:
|
|
r,w,e = select.select (rlist, [], [], 1)
|
|
except OSError as e:
|
|
if e.errno != errno.EINTR:
|
|
raise
|
|
|
|
if pipe.stdout in r:
|
|
data = pipe.stdout.read()
|
|
if data is not None:
|
|
outdata.append(data)
|
|
log.write(data)
|
|
|
|
if pipe.stderr in r:
|
|
data = pipe.stderr.read()
|
|
if data is not None:
|
|
errdata.append(data)
|
|
log.write(data)
|
|
|
|
readextras()
|
|
|
|
finally:
|
|
log.flush()
|
|
|
|
readextras()
|
|
|
|
if pipe.stdout is not None:
|
|
pipe.stdout.close()
|
|
if pipe.stderr is not None:
|
|
pipe.stderr.close()
|
|
return ''.join(outdata), ''.join(errdata)
|
|
|
|
def run(cmd, input=None, log=None, extrafiles=[], **options):
|
|
"""Convenience function to run a command and return its output, raising an
|
|
exception when the command fails"""
|
|
|
|
if isinstance(cmd, basestring) and not "shell" in options:
|
|
options["shell"] = True
|
|
|
|
try:
|
|
pipe = Popen(cmd, **options)
|
|
except OSError as exc:
|
|
if exc.errno == 2:
|
|
raise NotFoundError(cmd)
|
|
else:
|
|
raise CmdError(cmd, exc)
|
|
|
|
if log:
|
|
stdout, stderr = _logged_communicate(pipe, log, input, extrafiles)
|
|
else:
|
|
stdout, stderr = pipe.communicate(input)
|
|
|
|
if pipe.returncode != 0:
|
|
raise ExecutionError(cmd, pipe.returncode, stdout, stderr)
|
|
return stdout, stderr
|