"Fossies" - the Fresh Open Source Software Archive

Member "viewvc-1.2.1/lib/popen.py" (26 Mar 2020, 5532 Bytes) of package /linux/misc/viewvc-1.2.1.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.28_vs_1.2.1.

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