blob: 2adcb29c006d284ec740108dc1793bb9319cb6f7 [file] [log] [blame]
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
''' proc.py: subprocess and subprocess's stdout/stderr management '''
from threading import Thread
def _stream_process_fileno(fileno, handler):
""" Stream handling each line from fileno
:param filno: file object
:param handler: a function that will be called for each line from fileno
:return: None
"""
while 1:
line = fileno.readline()
handler(line)
if not line:
break
def stream_process_stdout(process, handler):
""" Stream the stdout for a process out to display
:param process: the process to stream the stdout for
:param handler: a function that will be called for each stdout line
:return: None
"""
_stream_process_fileno(process.stdout, handler)
def stream_process_stderr(process, handler):
""" Stream the stderr for a process out to display
:param process: the process to stream the stderr for
:param handler: a function that will be called for each stderr line
:return: None
"""
_stream_process_fileno(process.stderr, handler)
def _async_stream_process_output(process, stream_fn, handler):
""" Stream and handle the output of a process
:param process: the process to stream the output for
:param stream_fn: the function that applies handler to process
:param handler: a function that will be called for each log line
:return: None
"""
logging_thread = Thread(target=stream_fn, args=(process, handler, ))
# Setting the logging thread as a daemon thread will allow it to exit with the program
# rather than blocking the exit waiting for it to be handled manually.
logging_thread.daemon = True
logging_thread.start()
return logging_thread
def async_stream_process_stdout(process, handler):
""" Stream and handler the stdout of a process
:param process: the process to stream the stdout for
:param handler: a function that will be called to handle each line
:return: None
"""
return _async_stream_process_output(process, stream_process_stdout, handler)
def async_stream_process_stderr(process, handler):
""" Stream and handler the stderr of a process
:param process: the process to stream the stderr for
:param handler: a function that will be called to handle each line
:return: None
"""
return _async_stream_process_output(process, stream_process_stderr, handler)
class StringBuilder(object):
def __init__(self):
self.end = False
self.strs = []
def add(self, line):
if not line:
self.end = True
else:
self.strs.append(line)
def result(self):
while True:
if self.end:
return ''.join(self.strs)
else:
continue
def async_stdout_builder(proc):
""" Save stdout into string builder
:param proc: the process to save stdout for
:return StringBuilder
"""
stdout_builder = StringBuilder()
async_stream_process_stdout(proc, stdout_builder.add)
return stdout_builder
def async_stderr_builder(proc):
""" Save stderr into string builder
:param proc: the process to save stderr for
:return StringBuilder
"""
stderr_builder = StringBuilder()
async_stream_process_stderr(proc, stderr_builder.add)
return stderr_builder
def async_stdout_stderr_builder(proc):
""" Save stdout and stderr into string builders
:param proc: the process to save stdout and stderr for
:return (StringBuilder, StringBuilder)
"""
return async_stdout_builder(proc), async_stderr_builder(proc)