]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/shell.py
Remove string exception from remaster.
[wizard.git] / wizard / shell.py
index cda9eac34909d909f3e42d5a04810235cd051eaa..b8d4bd1e6dcfa8cda550c192b63a74a3146a435c 100644 (file)
@@ -55,6 +55,7 @@ class Shell(object):
     """
     def __init__(self, dry = False):
         self.dry = dry
+        self.cwd = None
     def call(self, *args, **kwargs):
         """
         Performs a system call.  The actual executable and options should
@@ -127,10 +128,16 @@ class Shell(object):
         # 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)
+        proc = subprocess.Popen(args, stdout=stdout, stderr=stderr, stdin=stdin, cwd=self.cwd, )
         if self._async(proc, args, **kwargs):
             return proc
         stdout, stderr = proc.communicate(kwargs["input"])
+        # can occur if we were doing interactive communication; i.e.
+        # we didn't pass in PIPE.
+        if stdout is None:
+            stdout = ""
+        if stderr is None:
+            stderr = ""
         if not kwargs["interactive"]:
             if kwargs["strip"]:
                 self._log(None, stderr)
@@ -151,7 +158,7 @@ class Shell(object):
             logging.debug("STDERR:\n" + stderr)
     def _wait(self):
         pass
-    def _async(self):
+    def _async(self, *args, **kwargs):
         return False
     def callAsUser(self, *args, **kwargs):
         """
@@ -188,6 +195,8 @@ class Shell(object):
         on working directory context.  Keyword arguments are the
         same as :meth:`call`.
         """
+        if os.getuid():
+            return self.call(*args, **kwargs)
         uid = os.stat(os.getcwd()).st_uid
         # consider also checking ruid?
         if uid != os.geteuid():
@@ -207,6 +216,12 @@ class Shell(object):
         """
         kwargs["strip"] = True
         return self.call(*args, **kwargs)
+    def setcwd(self, cwd):
+        """
+        Sets the directory processes are executed in. This sets a value
+        to be passed as the ``cwd`` argument to ``subprocess.Popen``.
+        """
+        self.cwd = cwd
 
 class ParallelShell(Shell):
     """
@@ -273,7 +288,7 @@ class ParallelShell(Shell):
         Blocking call that waits for an open subprocess slot.  This is
         automatically called by :meth:`Shell.call`.
         """
-        # XXX: This API sucks; the actuall call/callAsUser call should
+        # XXX: This API sucks; the actual call/callAsUser call should
         # probably block automatically (unless I have a good reason not to)
         # bail out immediately on initial ramp up
         if len(self.running) < self.max: return
@@ -307,6 +322,12 @@ class ParallelShell(Shell):
             return
         on_success(stdout, stderr)
 
+# Setup a convenience global instance
+shell = Shell()
+call = shell.call
+callAsUser = shell.callAsUser
+safeCall = shell.safeCall
+eval = shell.eval
 
 class DummyParallelShell(ParallelShell):
     """Same API as :class:`ParallelShell`, but doesn't actually