Source code for sts.util.procutils
# Copyright 2011-2013 Colin Scott
# Copyright 2011-2013 Andreas Wundsam
#
# Licensed 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.
import subprocess
import threading
import os
import sys
import time
import traceback
from sts.util.console import color
[docs]def split_up(f, l):
trues = []
falses = []
for elem in l:
if(f(elem)):
trues.append(elem)
else:
falses.append(elem)
return (trues, falses)
[docs]def kill_procs(child_processes, kill=None, verbose=True, timeout=5):
child_processes = filter(lambda e: e is not None, child_processes)
def msg(msg):
if(verbose):
sys.stderr.write(msg)
if kill == None:
if hasattr(kill_procs,"already_run"):
kill = True
else:
kill = False
kill_procs.already_run = True
if len(child_processes) == 0:
return
msg("%s child controllers..." % ("Killing" if kill else "Terminating"))
for child in child_processes:
if kill:
child.kill()
else:
child.terminate()
start_time = time.time()
last_dot = start_time
all_dead = []
while True:
(child_processes, new_dead) = split_up(lambda child: child.poll() is None, child_processes)
all_dead += new_dead
if len(child_processes) == 0:
break
if hasattr(time, "_orig_sleep"):
time._orig_sleep(0.1)
else:
time.sleep(0.1)
now = time.time()
if (now - last_dot) > 1:
msg(".")
last_dot = now
if (now - start_time) > timeout:
if kill:
break
else:
msg(' FAILED (timeout)!\n')
kill_procs(child_processes, kill=True)
break
for child in all_dead:
for attr_name in "stdin", "stdout", "stderr":
if hasattr(child, attr_name):
try:
attr = getattr(child, attr_name)
if attr:
attr.close()
except:
msg("Error closing child io.")
tb = traceback.format_exc()
msg(tb)
if len(child_processes) == 0:
msg(' OK\n')
printlock = threading.Lock()
def _prefix_thread(f, func):
def run():
while not f.closed:
line = f.readline()
if not line:
break
with printlock:
print func(line)
try:
sys.stderr.write("Closing fd %d\n" % f)
f.close() # idempotent, in case the f.closed broke out of the while loop
except:
# well, we tried
pass
t = threading.Thread(target=run)
t.daemon = True
t.start()
return t
[docs]def popen_filtered(name, args, cwd=None, env=None):
try:
cmd = subprocess.Popen(args, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=sys.stdin, cwd=cwd, env=env,
preexec_fn=lambda: os.setsid())
except OSError as e:
raise OSError("Error launching %s in directory %s: %s (error %d)" % (args, cwd, e.strerror, e.errno))
cmd._stdout_thread = _prefix_thread(cmd.stdout, lambda l: "%s%s %s%s\n" % (color.YELLOW, name, l.rstrip(), color.NORMAL))
cmd._stderr_thread = _prefix_thread(cmd.stderr, lambda l: "%s%s %s%s\n" % (color.B_RED + color.YELLOW, name, l.rstrip(), color.NORMAL))
return cmd