]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/shell.py
Implement web verification for pre-upgrade and post-upgrade.
[wizard.git] / wizard / shell.py
index c66147a0f9d876fe9fe10b2249d4cfd7f6771a49..8660d1ade198840e5c15d79ee1abb8fcdf30ff14 100644 (file)
@@ -25,12 +25,14 @@ def is_python(args):
     """Detects whether or not an argument list invokes a Python program."""
     return args[0] == "python" or args[0] == "wizard"
 
     """Detects whether or not an argument list invokes a Python program."""
     return args[0] == "python" or args[0] == "wizard"
 
-def drop_priviledges(dir, options):
+def drop_priviledges(dir, log_file):
     """
     Checks if we are running as root.  If we are, attempt to drop
     priviledges to the user who owns ``dir``, by re-calling
     itself using sudo with exec, such that the new process subsumes our
     """
     Checks if we are running as root.  If we are, attempt to drop
     priviledges to the user who owns ``dir``, by re-calling
     itself using sudo with exec, such that the new process subsumes our
-    current one.
+    current one.  If ``log_file`` is passed, the file is chown'ed
+    to the user we are dropping priviledges to, so the subprocess
+    can write to it.
     """
     if os.getuid():
         return
     """
     if os.getuid():
         return
@@ -43,7 +45,7 @@ def drop_priviledges(dir, options):
             args.append("%s=%s" % (k,v))
     args += sys.argv
     logging.debug("Dropping priviledges")
             args.append("%s=%s" % (k,v))
     args += sys.argv
     logging.debug("Dropping priviledges")
-    if options.log_file: os.chown(options.log_file, uid, -1)
+    if log_file: os.chown(log_file, uid, -1)
     os.execlp('sudo', 'sudo', '-u', '#' + str(uid), *args)
 
 class Shell(object):
     os.execlp('sudo', 'sudo', '-u', '#' + str(uid), *args)
 
 class Shell(object):
@@ -73,6 +75,9 @@ class Shell(object):
             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``.
             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 stdout:
+        :param stderr:
+        :param stdin: a file-type object that will be written to or read from as a pipe.
         :returns: a tuple of strings ``(stdout, stderr)``, or a string ``stdout``
             if ``strip`` is specified.
 
         :returns: a tuple of strings ``(stdout, stderr)``, or a string ``stdout``
             if ``strip`` is specified.
 
@@ -88,6 +93,9 @@ class Shell(object):
         kwargs.setdefault("strip", False)
         kwargs.setdefault("python", None)
         kwargs.setdefault("log", None)
         kwargs.setdefault("strip", False)
         kwargs.setdefault("python", None)
         kwargs.setdefault("log", None)
+        kwargs.setdefault("stdout", subprocess.PIPE)
+        kwargs.setdefault("stdin", subprocess.PIPE)
+        kwargs.setdefault("stderr", subprocess.PIPE)
         msg = "Running `" + ' '.join(args) + "`"
         if kwargs["strip"] and not kwargs["log"] is True or kwargs["log"] is False:
             logging.debug(msg)
         msg = "Running `" + ' '.join(args) + "`"
         if kwargs["strip"] and not kwargs["log"] is True or kwargs["log"] is False:
             logging.debug(msg)
@@ -108,9 +116,9 @@ class Shell(object):
             stdin=sys.stdin
             stderr=sys.stderr
         else:
             stdin=sys.stdin
             stderr=sys.stderr
         else:
-            stdout=subprocess.PIPE
-            stdin=subprocess.PIPE
-            stderr=subprocess.PIPE
+            stdout=kwargs["stdout"]
+            stdin=kwargs["stdin"]
+            stderr=kwargs["stderr"]
         # XXX: There is a possible problem here where we can fill up
         # the kernel buffer if we have 64KB of data.  This shouldn't
         # be a problem, and the fix for such case would be to write to
         # XXX: There is a possible problem here where we can fill up
         # the kernel buffer if we have 64KB of data.  This shouldn't
         # be a problem, and the fix for such case would be to write to
@@ -244,6 +252,13 @@ class ParallelShell(Shell):
         super(ParallelShell, self).__init__(dry=dry)
         self.running = {}
         self.max = max # maximum of commands to run in parallel
         super(ParallelShell, self).__init__(dry=dry)
         self.running = {}
         self.max = max # maximum of commands to run in parallel
+    @staticmethod
+    def make(no_parallelize, max):
+        """Convenience method oriented towards command modules."""
+        if no_parallelize:
+            return DummyParallelShell()
+        else:
+            return ParallelShell(max=max)
     def _async(self, proc, args, python, on_success, on_error, **kwargs):
         """
         Gets handed a :class:`subprocess.Proc` object from our deferred
     def _async(self, proc, args, python, on_success, on_error, **kwargs):
         """
         Gets handed a :class:`subprocess.Proc` object from our deferred