Process stdout and stderr from subprocesses separately
This commit is contained in:
parent
3a539a287b
commit
04aabd7d70
|
@ -74,3 +74,5 @@ def init(args):
|
||||||
log_handler._args = args
|
log_handler._args = args
|
||||||
handler.setFormatter(formatter)
|
handler.setFormatter(formatter)
|
||||||
root_logger.addHandler(handler)
|
root_logger.addHandler(handler)
|
||||||
|
|
||||||
|
logging.debug('*' * 40)
|
||||||
|
|
|
@ -16,8 +16,64 @@ GNU General Public License for more details.
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with pmbootstrap. If not, see <http://www.gnu.org/licenses/>.
|
along with pmbootstrap. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
import subprocess
|
|
||||||
import logging
|
import logging
|
||||||
|
import asyncio
|
||||||
|
import locale
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _execute(loop, args, cmd, log_message, log, return_stdout, check=True):
|
||||||
|
logging.debug(log_message)
|
||||||
|
|
||||||
|
class SubprocessProtocol(asyncio.SubprocessProtocol):
|
||||||
|
def __init__(self, future):
|
||||||
|
self.output = ""
|
||||||
|
self.error = ""
|
||||||
|
self.return_code = None
|
||||||
|
self._future = future
|
||||||
|
|
||||||
|
def pipe_data_received(self, fd, data):
|
||||||
|
nonlocal args
|
||||||
|
text = data.decode(locale.getpreferredencoding(False))
|
||||||
|
|
||||||
|
if fd == 1:
|
||||||
|
# stdout
|
||||||
|
if log:
|
||||||
|
args.logfd.write(text)
|
||||||
|
else:
|
||||||
|
print(text, end='')
|
||||||
|
self.output += text
|
||||||
|
|
||||||
|
elif fd == 2:
|
||||||
|
# stderr, possibly do something with color here
|
||||||
|
if log:
|
||||||
|
args.logfd.write(text)
|
||||||
|
else:
|
||||||
|
print(text, end='')
|
||||||
|
self.error += text
|
||||||
|
|
||||||
|
args.logfd.flush()
|
||||||
|
|
||||||
|
def process_exited(self):
|
||||||
|
self.return_code = 0
|
||||||
|
self._future.set_result(True)
|
||||||
|
|
||||||
|
exit_future = asyncio.Future(loop=loop)
|
||||||
|
create = loop.subprocess_exec(lambda: SubprocessProtocol(exit_future), *cmd)
|
||||||
|
transport, protocol = yield from create
|
||||||
|
yield from exit_future
|
||||||
|
transport.close()
|
||||||
|
|
||||||
|
return_code = transport.get_returncode()
|
||||||
|
if return_code != 0 and False:
|
||||||
|
if check:
|
||||||
|
raise RuntimeError("Command failed: \n" + protocol.error)
|
||||||
|
print('Program exited with: {}'.format(transport.get_returncode()))
|
||||||
|
|
||||||
|
if return_stdout:
|
||||||
|
return protocol.output
|
||||||
|
else:
|
||||||
|
return return_code
|
||||||
|
|
||||||
|
|
||||||
def core(args, cmd, log_message, log, return_stdout, check=True):
|
def core(args, cmd, log_message, log, return_stdout, check=True):
|
||||||
|
@ -26,33 +82,14 @@ def core(args, cmd, log_message, log, return_stdout, check=True):
|
||||||
Run the command and write the output to the log.
|
Run the command and write the output to the log.
|
||||||
|
|
||||||
:param check: raise an exception, when the command fails
|
:param check: raise an exception, when the command fails
|
||||||
|
:param log: send output to log instead of stdout
|
||||||
|
:param return_stdout: return the stdout from the called process
|
||||||
"""
|
"""
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
try:
|
loop.set_debug(False)
|
||||||
ret = None
|
task = _execute(loop, args, cmd, log_message, log, return_stdout, check)
|
||||||
if log:
|
result = loop.run_until_complete(task)
|
||||||
if return_stdout:
|
return result
|
||||||
ret = subprocess.check_output(cmd).decode("utf-8")
|
|
||||||
args.logfd.write(ret)
|
|
||||||
else:
|
|
||||||
subprocess.check_call(cmd, stdout=args.logfd,
|
|
||||||
stderr=args.logfd)
|
|
||||||
args.logfd.flush()
|
|
||||||
else:
|
|
||||||
logging.debug("*** output passed to pmbootstrap stdout, not" +
|
|
||||||
" to this log ***")
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
|
|
||||||
except subprocess.CalledProcessError as exc:
|
|
||||||
if check:
|
|
||||||
if log:
|
|
||||||
logging.debug("^" * 70)
|
|
||||||
logging.info("NOTE: The failed command's output is above"
|
|
||||||
" the ^^^ line in the logfile: " + args.log)
|
|
||||||
raise RuntimeError("Command failed: " + log_message) from exc
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def user(args, cmd, log=True, working_dir=None, return_stdout=False,
|
def user(args, cmd, log=True, working_dir=None, return_stdout=False,
|
||||||
|
|
Loading…
Reference in New Issue