Source code for sdss_access.sync.system_call
# License information goes here
# -*- coding: utf-8 -*-
#
# $Id: system_call.py 157318 2014-06-29 12:10:03Z weaver $
#
"""
"""
#
# This will help with 2to3 support.
#
from __future__ import absolute_import, division, print_function, unicode_literals
#
#
#
[docs]
def system_call(command,test=False,logger=None,logall=False,message=None,outname=None,errname=None):
"""A convenient wrapper to log and perform system calls.
Parameters
----------
command : str
The system command to run. It will be split internally by shlex.split().
test : bool, optional
Set this to true to not actually run the commands.
logger : logging.logging, optional
If passed a logging object, diagnostic output will be set to this object.
logall : bool, optional
Set this to true to always log stdout and stderr (at level DEBUG).
Otherwise stdout and stderr will only be logged for nonzero status
message : str, optional
Call logger.critical(message) with this message and then call
sys.exit(status).
outname : str, optional
If set, use ``outname`` as the name of a file to contain stdout. It
is the responsibility of the caller of this function to clean up
the resulting file. Otherwise a temporary file will be used.
errname : str, optional
Same as ``outname``, but will contain stderr.
Returns
-------
(status,out,err) : tuple
The exit status, stdout and stderr of the process
Examples
--------
>>> status,out,err = transfer.common.system_call('date')
"""
from math import log10
from sys import exit
from subprocess import Popen
from shlex import split
from tempfile import TemporaryFile
from time import time, sleep
if logger is not None:
logger.debug(command)
status = 0
out = ''
err = ''
# if test, return early
if test:
return (status, out, err)
# Perform the system call
if outname is None:
outfile = TemporaryFile()
else:
outfile = open(outname, 'w+')
if errname is None:
errfile = TemporaryFile()
else:
errfile = open(errname, 'w+')
proc = Popen(split(str(command)), stdout=outfile, stderr=errfile)
tstart = time()
while proc.poll() is None:
elapsed = time() - tstart
if elapsed > 500000:
message = "Process still running after more than 5 days!"
proc.kill()
break
tsleep = 10**(int(log10(elapsed)) - 1)
if tsleep < 1:
tsleep = 1
sleep(tsleep)
# proc.wait()
status = proc.returncode
outfile.seek(0)
out = outfile.read()
errfile.seek(0)
err = errfile.read()
outfile.close()
errfile.close()
if logger is not None:
if status == 0 and logall:
if len(out) > 0:
logger.debug('STDOUT = \n' + out)
if len(err) > 0:
logger.debug('STDERR = \n' + err)
if status != 0:
logger.error('status = {0}'.format(status))
if len(out) > 0:
logger.error('STDOUT = \n' + out)
if len(err) > 0:
logger.error('STDERR = \n' + err)
if message is not None:
logger.critical(message)
exit(status)
return (status, out, err)