#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Andre Anjos <andre.anjos@idiap.ch>
# Wed 24 Aug 2011 09:20:40 CEST
"""Wrappers for Idiap's SETSHELL functionality
"""
import os
import signal
import subprocess
import sys
from .tools import logger, str_
[docs]def environ(context):
"""Retrieves the environment for a particular SETSHELL context"""
if "BASEDIRSETSHELL" not in os.environ:
# It seems that we are in a hostile environment
# try to source the Idiap-wide shell
idiap_source = "/idiap/resource/software/initfiles/shrc"
if os.path.exists(idiap_source):
logger.debug("Sourcing: '%s'" % idiap_source)
try:
command = ["bash", "-c", "source %s && env" % idiap_source]
pi = subprocess.Popen(command, stdout=subprocess.PIPE)
# overwrite the default environment
for line in pi.stdout:
line = str_(line)
(key, _, value) = line.partition("=")
os.environ[key.strip()] = value.strip()
except OSError:
# occurs when the file is not executable or not found
pass
# in case the BASEDIRSETSHELL environment variable is not set,
# we are not at Idiap,
# and so we don't have to set any additional variables.
if "BASEDIRSETSHELL" not in os.environ:
return dict(os.environ)
BASEDIRSETSHELL = os.environ["BASEDIRSETSHELL"]
dosetshell = "%s/setshell/bin/dosetshell" % BASEDIRSETSHELL
command = [dosetshell, "-s", "sh", context]
# First things first, we get the path to the temp file created by dosetshell
try:
logger.debug("Executing: '%s'", " ".join(command))
p = subprocess.Popen(command, stdout=subprocess.PIPE)
except OSError as e:
# occurs when the file is not executable or not found
raise OSError(
"Error executing '%s': %s (%d)"
% (" ".join(command), e.strerror, e.errno)
)
try:
source = str_(p.communicate()[0]).strip()
except KeyboardInterrupt: # the user CTRL-C'ed
os.kill(p.pid, signal.SIGTERM)
sys.exit(signal.SIGTERM)
# We have now the name of the source file, source it and erase it
command2 = ["bash", "-c", "source %s && env" % source]
try:
logger.debug("Executing: '%s'", " ".join(command2))
p2 = subprocess.Popen(command2, stdout=subprocess.PIPE)
except OSError as e:
# occurs when the file is not executable or not found
raise OSError(
"Error executing '%s': %s (%d)"
% (" ".join(command2), e.strerror, e.errno)
)
new_environ = dict(os.environ)
for line in p2.stdout:
line = str_(line)
(key, _, value) = line.partition("=")
new_environ[key.strip()] = value.strip()
try:
p2.communicate()
except KeyboardInterrupt: # the user CTRL-C'ed
os.kill(p2.pid, signal.SIGTERM)
sys.exit(signal.SIGTERM)
if os.path.exists(source):
os.unlink(source)
logger.debug("Discovered environment for context '%s':", context)
for k in sorted(new_environ.keys()):
logger.debug(" %s = %s", k, new_environ[k])
return new_environ
[docs]def sexec(context, command, error_on_nonzero=True):
"""Executes a command within a particular Idiap SETSHELL context"""
import six
if isinstance(context, six.string_types):
E = environ(context)
else:
E = context
try:
logger.debug("Executing: '%s'", " ".join(command))
p = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=E
)
(stdout, stderr) = p.communicate() # note: stderr will be 'None'
if p.returncode != 0:
if error_on_nonzero:
raise RuntimeError(
"Execution of '%s' exited with status != 0 (%d): %s"
% (" ".join(command), p.returncode, str_(stdout))
)
else:
logger.debug(
"Execution of '%s' exited with status != 0 (%d): %s"
% (" ".join(command), p.returncode, str_(stdout))
)
return stdout.strip()
except KeyboardInterrupt: # the user CTRC-C'ed
os.kill(p.pid, signal.SIGTERM)
sys.exit(signal.SIGTERM)
[docs]def replace(context, command):
E = environ(context)
os.execvpe(command[0], command, E)