summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/process.py
diff options
context:
space:
mode:
authorChris Larson <chris_larson@mentor.com>2010-12-09 20:14:40 -0500
committerRichard Purdie <rpurdie@linux.intel.com>2011-01-04 14:46:47 +0000
commit87b6cdf5475c6fcc2368e1d80dfaac8fdee5a453 (patch)
tree921cf7b191b3ad23df1ffd2b9ce9d39fb41f51ff /bitbake/lib/bb/process.py
parentc8d2dad04960746d38d28bb2c5aba8363534541a (diff)
downloadpoky-87b6cdf5475c6fcc2368e1d80dfaac8fdee5a453.tar.gz
process: add subprocess-based bits
(Bitbake rev: c63e55564a8840083dbd8634b10fe6f76d1f1354) Signed-off-by: Chris Larson <chris_larson@mentor.com> Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'bitbake/lib/bb/process.py')
-rw-r--r--bitbake/lib/bb/process.py107
1 files changed, 107 insertions, 0 deletions
diff --git a/bitbake/lib/bb/process.py b/bitbake/lib/bb/process.py
new file mode 100644
index 0000000000..b022e4c8f9
--- /dev/null
+++ b/bitbake/lib/bb/process.py
@@ -0,0 +1,107 @@
1import subprocess
2import signal
3import logging
4
5logger = logging.getLogger('BitBake.Process')
6
7def subprocess_setup():
8 # Python installs a SIGPIPE handler by default. This is usually not what
9 # non-Python subprocesses expect.
10 print('in preexec hook')
11 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
12
13class CmdError(RuntimeError):
14 def __init__(self, command):
15 self.command = command
16
17 def __str__(self):
18 if not isinstance(self.command, basestring):
19 cmd = subprocess.list2cmdline(self.command)
20 else:
21 cmd = self.command
22
23 return "Execution of '%s' failed" % cmd
24
25class NotFoundError(CmdError):
26 def __str__(self):
27 return CmdError.__str__(self) + ": command not found"
28
29class ExecutionError(CmdError):
30 def __init__(self, command, exitcode, stdout = None, stderr = None):
31 CmdError.__init__(self, command)
32 self.exitcode = exitcode
33 self.stdout = stdout
34 self.stderr = stderr
35
36 def __str__(self):
37 message = ""
38 if self.stderr:
39 message += self.stderr
40 if self.stdout:
41 message += self.stdout
42 if message:
43 message = ":\n" + message
44 return (CmdError.__str__(self) +
45 " with exit code %s" % self.exitcode + message)
46
47class Popen(subprocess.Popen):
48 defaults = {
49 "close_fds": True,
50 "preexec_fn": subprocess_setup,
51 "stdout": subprocess.PIPE,
52 "stderr": subprocess.STDOUT,
53 "stdin": subprocess.PIPE,
54 "shell": False,
55 }
56
57 def __init__(self, *args, **kwargs):
58 options = dict(self.defaults)
59 options.update(kwargs)
60 subprocess.Popen.__init__(self, *args, **options)
61
62def _logged_communicate(pipe, log, input):
63 bufsize = 512
64 hasoutput = pipe.stdout is not None or pipe.stderr is not None
65 if hasoutput:
66 outdata, errdata = [], []
67 while pipe.poll() is None:
68 if pipe.stdout is not None:
69 data = pipe.stdout.read(bufsize)
70 if data is not None:
71 outdata.append(data)
72 log.write(data)
73
74 if pipe.stderr is not None:
75 data = pipe.stderr.read(bufsize)
76 if data is not None:
77 errdata.append(data)
78 log.write(data)
79 return ''.join(outdata), ''.join(errdata)
80
81def run(cmd, input=None, **options):
82 """Convenience function to run a command and return its output, raising an
83 exception when the command fails"""
84
85 if isinstance(cmd, basestring) and not "shell" in options:
86 options["shell"] = True
87
88 log = options.get('log')
89 if log:
90 del options['log']
91
92 try:
93 pipe = Popen(cmd, **options)
94 except OSError, exc:
95 if exc.errno == 2:
96 raise NotFoundError(cmd)
97 else:
98 raise
99
100 if log:
101 stdout, stderr = _logged_communicate(pipe, log, input)
102 else:
103 stdout, stderr = pipe.communicate(input)
104
105 if pipe.returncode != 0:
106 raise ExecutionError(cmd, pipe.returncode, stdout, stderr)
107 return stdout, stderr