"Fossies" - the Fresh Open Source Software Archive

Member "viewvc-1.1.27/lib/popen.py" (6 Jun 2019, 5573 Bytes) of package /linux/misc/viewvc-1.1.27.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "popen.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.1.26_vs_1.1.27.

    1 # -*-python-*-
    2 #
    3 # Copyright (C) 1999-2019 The ViewCVS Group. All Rights Reserved.
    4 #
    5 # By using this file, you agree to the terms and conditions set forth in
    6 # the LICENSE.html file which can be found at the top level of the ViewVC
    7 # distribution or at http://viewvc.org/license-1.html.
    8 #
    9 # For more information, visit http://viewvc.org/
   10 #
   11 # -----------------------------------------------------------------------
   12 #
   13 # popen.py: a replacement for os.popen()
   14 #
   15 # This implementation of popen() provides a cmd + args calling sequence,
   16 # rather than a system() type of convention. The shell facilities are not
   17 # available, but that implies we can avoid worrying about shell hacks in
   18 # the arguments.
   19 #
   20 # -----------------------------------------------------------------------
   21 
   22 import os
   23 import sys
   24 import sapi
   25 import threading
   26 import string
   27 
   28 if sys.platform == "win32":
   29   import win32popen
   30   import win32event
   31   import win32process
   32   import debug
   33   import StringIO
   34 
   35 def popen(cmd, args, mode, capture_err=1):
   36   if sys.platform == "win32":
   37     command = win32popen.CommandLine(cmd, args)
   38 
   39     if string.find(mode, 'r') >= 0:
   40       hStdIn = None
   41 
   42       if debug.SHOW_CHILD_PROCESSES:
   43         dbgIn, dbgOut = None, StringIO.StringIO()
   44 
   45         handle, hStdOut = win32popen.MakeSpyPipe(0, 1, (dbgOut,))
   46 
   47         if capture_err:
   48           hStdErr = hStdOut
   49           dbgErr = dbgOut
   50         else:
   51           dbgErr = StringIO.StringIO()
   52           x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
   53       else:
   54         handle, hStdOut = win32popen.CreatePipe(0, 1)
   55         if capture_err:
   56           hStdErr = hStdOut
   57         else:
   58           hStdErr = win32popen.NullFile(1)
   59 
   60     else:
   61       if debug.SHOW_CHILD_PROCESSES:
   62         dbgIn, dbgOut, dbgErr = StringIO.StringIO(), StringIO.StringIO(), StringIO.StringIO()
   63         hStdIn, handle = win32popen.MakeSpyPipe(1, 0, (dbgIn,))
   64         x, hStdOut = win32popen.MakeSpyPipe(None, 1, (dbgOut,))
   65         x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
   66       else:
   67         hStdIn, handle = win32popen.CreatePipe(0, 1)
   68         hStdOut = None
   69         hStdErr = None
   70 
   71     phandle, pid, thandle, tid = win32popen.CreateProcess(command, hStdIn, hStdOut, hStdErr)
   72 
   73     if debug.SHOW_CHILD_PROCESSES:
   74       debug.Process(command, dbgIn, dbgOut, dbgErr)
   75 
   76     return _pipe(win32popen.File2FileObject(handle, mode), phandle)
   77 
   78   # flush the stdio buffers since we are about to change the FD under them
   79   sys.stdout.flush()
   80   sys.stderr.flush()
   81 
   82   r, w = os.pipe()
   83   pid = os.fork()
   84   if pid:
   85     # in the parent
   86 
   87     # close the descriptor that we don't need and return the other one.
   88     if string.find(mode, 'r') >= 0:
   89       os.close(w)
   90       return _pipe(os.fdopen(r, mode), pid)
   91     os.close(r)
   92     return _pipe(os.fdopen(w, mode), pid)
   93 
   94   # in the child
   95 
   96   # we'll need /dev/null for the discarded I/O
   97   null = os.open('/dev/null', os.O_RDWR)
   98 
   99   if string.find(mode, 'r') >= 0:
  100     # hook stdout/stderr to the "write" channel
  101     os.dup2(w, 1)
  102     # "close" stdin; the child shouldn't use it
  103     ### this isn't quite right... we may want the child to read from stdin
  104     os.dup2(null, 0)
  105     # what to do with errors?
  106     if capture_err:
  107       os.dup2(w, 2)
  108     else:
  109       os.dup2(null, 2)
  110   else:
  111     # hook stdin to the "read" channel
  112     os.dup2(r, 0)
  113     # "close" stdout/stderr; the child shouldn't use them
  114     ### this isn't quite right... we may want the child to write to these
  115     os.dup2(null, 1)
  116     os.dup2(null, 2)
  117 
  118   # don't need these FDs any more
  119   os.close(null)
  120   os.close(r)
  121   os.close(w)
  122 
  123   # the stdin/stdout/stderr are all set up. exec the target
  124   try:
  125     os.execvp(cmd, (cmd,) + tuple(args))
  126   except:
  127     # aid debugging, if the os.execvp above fails for some reason:
  128     print "<h2>exec failed:</h2><pre>", cmd, string.join(args), "</pre>"
  129     raise
  130 
  131   # crap. shouldn't be here.
  132   sys.exit(127)
  133 
  134 class _pipe:
  135   "Wrapper for a file which can wait() on a child process at close time."
  136 
  137   def __init__(self, file, child_pid, done_event = None, thread = None):
  138     self.file = file
  139     self.child_pid = child_pid
  140     if sys.platform == "win32":
  141       if done_event:
  142         self.wait_for = (child_pid, done_event)
  143       else:
  144         self.wait_for = (child_pid,)
  145     else:
  146       self.thread = thread
  147 
  148   def eof(self):
  149     ### should be calling file.eof() here instead of file.close(), there
  150     ### may be data in the pipe or buffer after the process exits
  151     if sys.platform == "win32":
  152       r = win32event.WaitForMultipleObjects(self.wait_for, 1, 0)
  153       if r == win32event.WAIT_OBJECT_0:
  154         self.file.close()
  155         self.file = None
  156         return win32process.GetExitCodeProcess(self.child_pid)
  157       return None
  158 
  159     if self.thread and self.thread.isAlive():
  160       return None
  161 
  162     pid, status = os.waitpid(self.child_pid, os.WNOHANG)
  163     if pid:
  164       self.file.close()
  165       self.file = None
  166       return status
  167     return None
  168 
  169   def close(self):
  170     if self.file:
  171       self.file.close()
  172       self.file = None
  173       if sys.platform == "win32":
  174         win32event.WaitForMultipleObjects(self.wait_for, 1, win32event.INFINITE)
  175         return win32process.GetExitCodeProcess(self.child_pid)
  176       else:
  177         if self.thread:
  178           self.thread.join()
  179         if type(self.child_pid) == type([]):
  180           for pid in self.child_pid:
  181             exit = os.waitpid(pid, 0)[1]
  182           return exit
  183         else:
  184           return os.waitpid(self.child_pid, 0)[1]
  185     return None
  186 
  187   def __getattr__(self, name):
  188     return getattr(self.file, name)
  189 
  190   def __del__(self):
  191     self.close()