Source code for emop.lib.utilities

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_max_rss(): """ Returns max RSS soft ulimit in bytes """ _soft, _hard = resource.getrlimit(resource.RLIMIT_RSS) return _soft
[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