specify this if you are using another wrapper around this function).
:param log: if True, we log the call as INFO, if False, we log the call
as DEBUG, otherwise, we detect based on ``strip``.
+ :param addenv: mapping of environment variables *to add*
:param stdout:
:param stderr:
:param stdin: a file-type object that will be written to or read from as a pipe.
kwargs.setdefault("stdout", subprocess.PIPE)
kwargs.setdefault("stdin", subprocess.PIPE)
kwargs.setdefault("stderr", subprocess.PIPE)
+ kwargs.setdefault("addenv", None)
msg = "Running `" + ' '.join(args) + "`"
if kwargs["strip"] and not kwargs["log"] is True or kwargs["log"] is False:
logging.debug(msg)
stdout=kwargs["stdout"]
stdin=kwargs["stdin"]
stderr=kwargs["stderr"]
+ env = None
+ if kwargs["addenv"]:
+ env = dict(os.environ.items() + kwargs["addenv"].items())
# XXX: There is a possible problem here where we can fill up
# the kernel buffer if we have 64KB of data. This shouldn't
# normally be a problem, and the fix for such case would be to write to
# waitpid() pump to a select() pump, creating a pipe to
# ourself, and then setting up a SIGCHILD handler to write a single
# byte to the pipe to get us out of select() when a subprocess exits.
- proc = subprocess.Popen(args, stdout=stdout, stderr=stderr, stdin=stdin, cwd=self.cwd, )
+ proc = subprocess.Popen(args, stdout=stdout, stderr=stderr, stdin=stdin, cwd=self.cwd, env=env)
if self._async(proc, args, **kwargs):
return proc
stdout, stderr = proc.communicate(kwargs["input"])
to be passed as the ``cwd`` argument to ``subprocess.Popen``.
"""
self.cwd = cwd
+ def interactive():
+ user_shell = os.getenv("SHELL")
+ if not user_shell: user_shell = "/bin/bash"
+ # XXX: scripts specific hack, since mbash doesn't respect the current working directory
+ # When the revolution comes (i.e. $ATHENA_HOMEDIR/Scripts is your Scripts home
+ # directory) this isn't strictly necessary, but we'll probably need to support
+ # web_scripts directories ad infinitum.
+ if user_shell == "/usr/local/bin/mbash": user_shell = "/bin/bash"
+
+ try:
+ self.call(user_shell, "-i", interactive=True)
+ except shell.CallError as e:
+ logging.warning("Shell returned non-zero exit code %d" % e.code)
class ParallelShell(Shell):
"""
on_error(eclass(proc.returncode, args, stdout, stderr))
return
on_success(stdout, stderr)
+ def interactive():
+ raise Error("Cannot use interactive() on parallel shell")
# Setup a convenience global instance
shell = Shell()
callAsUser = shell.callAsUser
safeCall = shell.safeCall
eval = shell.eval
+interactive = shell.interactive
class DummyParallelShell(ParallelShell):
"""Same API as :class:`ParallelShell`, but doesn't actually