import collections
import errno
import logging
import os
import resource
import shlex
import shutil
import signal
import subprocess32
logger = logging.getLogger('emop')
[docs]def get_temp_dir():
"""Gets the temp directory based on environment variables
Currently searched environment variables:
* TMPDIR
Returns:
str: Path to temp directory.
"""
env_vars = [
'TMPDIR',
]
tmp_dir = None
for env_var in env_vars:
if os.environ.get(env_var):
tmp_dir = os.environ.get(env_var)
logger.debug("Using temp directory %s" % tmp_dir)
return tmp_dir
if not tmp_dir:
logger.error("Temporary directory could not be found.")
return tmp_dir
[docs]def mkdirs_exists_ok(path):
"""Wrapper for os.makedirs
This function is needed to avoid race conditions
when the directory exists when attempting to use
os.makedirs. This emulates the behavior of Python 3.x
os.makedirs exist_ok argument.
Args:
path (str): Path of directory to create
"""
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
[docs]def recursive_copy(src, dest, ignore=None, exclude=[]):
"""Recursive file copy
This method is currently not used, but left incase would be needed in the future.
"""
if os.path.isdir(src):
if not os.path.isdir(dest):
mkdirs_exists_ok(dest)
files = os.listdir(src)
for f in files:
_src = os.path.join(src, f)
_dest = os.path.join(dest, f)
if f not in exclude and _src not in exclude:
recursive_copy(src=_src, dest=_dest, exclude=exclude)
else:
logger.debug("Copy %s -> %s", src, dest)
shutil.copyfile(src, dest)
[docs]def exec_cmd(cmd, log_level="info", timeout=-1, realtime=False):
"""Executes a command
This is the method used by this application to execute
shell commands.
If the cmd argument can be a 2D list but only one level deep.
The command's stdout, stderr and exitcode are turned as a namedtuple.
Args:
cmd (str or list): Command to execute
log_level (str, optional): log level when printing information about the command being executed.
timeout (int, optional): The time in seconds the command should be allowed to run before timing out.
Returns:
tuple: (stdout, stderr, exitcode)
"""
# REF: http://stackoverflow.com/a/3326559
Proc = collections.namedtuple('Proc', ['stdout', 'stderr', 'exitcode'])
if timeout == -1:
timeout = None
if isinstance(cmd, basestring):
cmd_str = cmd
cmd = shlex.split(cmd)
elif isinstance(cmd, list):
cmd_flat = []
for i in cmd:
if isinstance(i, list):
for j in i:
cmd_flat.append(j)
else:
cmd_flat.append(i)
cmd = cmd_flat
cmd_str = " ".join(cmd)
getattr(logger, log_level)("Executing: '%s'" % cmd_str)
try:
# TODO Eventually may just need to redirect all stderr to stdout for simplicity
# process = subprocess32.Popen(cmd, stdout=subprocess32.PIPE, stderr=subprocess32.STDOUT, env=os.environ)
process = subprocess32.Popen(cmd, stdout=subprocess32.PIPE, stderr=subprocess32.PIPE, env=os.environ)
if realtime:
for line in iter(process.stdout.readline, b''):
getattr(logger, log_level)(line.strip())
process.stdout.close()
retval = process.wait(timeout=timeout)
out = process.stdout
err = process.stderr
else:
out, err = process.communicate(timeout=timeout)
retval = process.returncode
return Proc(stdout=out, stderr=err, exitcode=retval)
except subprocess32.TimeoutExpired:
process.kill()
timeout_msg = "Command timed out"
return Proc(stdout=timeout_msg, stderr=timeout_msg, exitcode=1)
except OSError as e:
if e.errno == os.errno.ENOENT:
error_msg = "File not found for command: %s" % e
return Proc(stdout=error_msg, stderr=error_msg, exitcode=1)
else:
raise