midori/waf-modules/wafadmin/pproc.py
2013-10-23 20:26:27 -07:00

496 lines
14 KiB
Python

#! /usr/bin/env python
# encoding: utf-8
import sys
mswindows=(sys.platform=="win32")
import os
import types
import traceback
import gc
class CalledProcessError(Exception):
def __init__(self,returncode,cmd):
self.returncode=returncode
self.cmd=cmd
def __str__(self):
return"Command '%s' returned non-zero exit status %d"%(self.cmd,self.returncode)
if mswindows:
import threading
import msvcrt
if 0:
import pywintypes
from win32api import GetStdHandle,STD_INPUT_HANDLE,STD_OUTPUT_HANDLE,STD_ERROR_HANDLE
from win32api import GetCurrentProcess,DuplicateHandle,GetModuleFileName,GetVersion
from win32con import DUPLICATE_SAME_ACCESS,SW_HIDE
from win32pipe import CreatePipe
from win32process import CreateProcess,STARTUPINFO,GetExitCodeProcess,STARTF_USESTDHANDLES,STARTF_USESHOWWINDOW,CREATE_NEW_CONSOLE
from win32event import WaitForSingleObject,INFINITE,WAIT_OBJECT_0
else:
from _subprocess import*
class STARTUPINFO:
dwFlags=0
hStdInput=None
hStdOutput=None
hStdError=None
wShowWindow=0
class pywintypes:
error=IOError
else:
import select
import errno
import fcntl
import pickle
__all__=["Popen","PIPE","STDOUT","call","check_call","CalledProcessError"]
try:
MAXFD=os.sysconf("SC_OPEN_MAX")
except:
MAXFD=256
try:
False
except NameError:
False=0
True=1
_active=[]
def _cleanup():
for inst in _active[:]:
if inst.poll(_deadstate=sys.maxint)>=0:
try:
_active.remove(inst)
except ValueError:
pass
PIPE=-1
STDOUT=-2
def call(*popenargs,**kwargs):
return Popen(*popenargs,**kwargs).wait()
def check_call(*popenargs,**kwargs):
retcode=call(*popenargs,**kwargs)
cmd=kwargs.get("args")
if cmd is None:
cmd=popenargs[0]
if retcode:
raise CalledProcessError(retcode,cmd)
return retcode
def list2cmdline(seq):
result=[]
needquote=False
for arg in seq:
bs_buf=[]
if result:
result.append(' ')
needquote=(" "in arg)or("\t"in arg)or arg==""
if needquote:
result.append('"')
for c in arg:
if c=='\\':
bs_buf.append(c)
elif c=='"':
result.append('\\'*len(bs_buf)*2)
bs_buf=[]
result.append('\\"')
else:
if bs_buf:
result.extend(bs_buf)
bs_buf=[]
result.append(c)
if bs_buf:
result.extend(bs_buf)
if needquote:
result.extend(bs_buf)
result.append('"')
return''.join(result)
class Popen(object):
def __init__(self,args,bufsize=0,executable=None,stdin=None,stdout=None,stderr=None,preexec_fn=None,close_fds=False,shell=False,cwd=None,env=None,universal_newlines=False,startupinfo=None,creationflags=0):
_cleanup()
self._child_created=False
if not isinstance(bufsize,(int,long)):
raise TypeError("bufsize must be an integer")
if mswindows:
if preexec_fn is not None:
raise ValueError("preexec_fn is not supported on Windows platforms")
if close_fds:
raise ValueError("close_fds is not supported on Windows platforms")
else:
if startupinfo is not None:
raise ValueError("startupinfo is only supported on Windows platforms")
if creationflags!=0:
raise ValueError("creationflags is only supported on Windows platforms")
self.stdin=None
self.stdout=None
self.stderr=None
self.pid=None
self.returncode=None
self.universal_newlines=universal_newlines
(p2cread,p2cwrite,c2pread,c2pwrite,errread,errwrite)=self._get_handles(stdin,stdout,stderr)
self._execute_child(args,executable,preexec_fn,close_fds,cwd,env,universal_newlines,startupinfo,creationflags,shell,p2cread,p2cwrite,c2pread,c2pwrite,errread,errwrite)
if mswindows:
if stdin is None and p2cwrite is not None:
os.close(p2cwrite)
p2cwrite=None
if stdout is None and c2pread is not None:
os.close(c2pread)
c2pread=None
if stderr is None and errread is not None:
os.close(errread)
errread=None
if p2cwrite:
self.stdin=os.fdopen(p2cwrite,'wb',bufsize)
if c2pread:
if universal_newlines:
self.stdout=os.fdopen(c2pread,'rU',bufsize)
else:
self.stdout=os.fdopen(c2pread,'rb',bufsize)
if errread:
if universal_newlines:
self.stderr=os.fdopen(errread,'rU',bufsize)
else:
self.stderr=os.fdopen(errread,'rb',bufsize)
def _translate_newlines(self,data):
data=data.replace("\r\n","\n")
data=data.replace("\r","\n")
return data
def __del__(self,sys=sys):
if not self._child_created:
return
self.poll(_deadstate=sys.maxint)
if self.returncode is None and _active is not None:
_active.append(self)
def communicate(self,input=None):
if[self.stdin,self.stdout,self.stderr].count(None)>=2:
stdout=None
stderr=None
if self.stdin:
if input:
self.stdin.write(input)
self.stdin.close()
elif self.stdout:
stdout=self.stdout.read()
elif self.stderr:
stderr=self.stderr.read()
self.wait()
return(stdout,stderr)
return self._communicate(input)
if mswindows:
def _get_handles(self,stdin,stdout,stderr):
if stdin is None and stdout is None and stderr is None:
return(None,None,None,None,None,None)
p2cread,p2cwrite=None,None
c2pread,c2pwrite=None,None
errread,errwrite=None,None
if stdin is None:
p2cread=GetStdHandle(STD_INPUT_HANDLE)
if p2cread is not None:
pass
elif stdin is None or stdin==PIPE:
p2cread,p2cwrite=CreatePipe(None,0)
p2cwrite=p2cwrite.Detach()
p2cwrite=msvcrt.open_osfhandle(p2cwrite,0)
elif isinstance(stdin,int):
p2cread=msvcrt.get_osfhandle(stdin)
else:
p2cread=msvcrt.get_osfhandle(stdin.fileno())
p2cread=self._make_inheritable(p2cread)
if stdout is None:
c2pwrite=GetStdHandle(STD_OUTPUT_HANDLE)
if c2pwrite is not None:
pass
elif stdout is None or stdout==PIPE:
c2pread,c2pwrite=CreatePipe(None,0)
c2pread=c2pread.Detach()
c2pread=msvcrt.open_osfhandle(c2pread,0)
elif isinstance(stdout,int):
c2pwrite=msvcrt.get_osfhandle(stdout)
else:
c2pwrite=msvcrt.get_osfhandle(stdout.fileno())
c2pwrite=self._make_inheritable(c2pwrite)
if stderr is None:
errwrite=GetStdHandle(STD_ERROR_HANDLE)
if errwrite is not None:
pass
elif stderr is None or stderr==PIPE:
errread,errwrite=CreatePipe(None,0)
errread=errread.Detach()
errread=msvcrt.open_osfhandle(errread,0)
elif stderr==STDOUT:
errwrite=c2pwrite
elif isinstance(stderr,int):
errwrite=msvcrt.get_osfhandle(stderr)
else:
errwrite=msvcrt.get_osfhandle(stderr.fileno())
errwrite=self._make_inheritable(errwrite)
return(p2cread,p2cwrite,c2pread,c2pwrite,errread,errwrite)
def _make_inheritable(self,handle):
return DuplicateHandle(GetCurrentProcess(),handle,GetCurrentProcess(),0,1,DUPLICATE_SAME_ACCESS)
def _find_w9xpopen(self):
w9xpopen=os.path.join(os.path.dirname(GetModuleFileName(0)),"w9xpopen.exe")
if not os.path.exists(w9xpopen):
w9xpopen=os.path.join(os.path.dirname(sys.exec_prefix),"w9xpopen.exe")
if not os.path.exists(w9xpopen):
raise RuntimeError("Cannot locate w9xpopen.exe, which is needed for Popen to work with your shell or platform.")
return w9xpopen
def _execute_child(self,args,executable,preexec_fn,close_fds,cwd,env,universal_newlines,startupinfo,creationflags,shell,p2cread,p2cwrite,c2pread,c2pwrite,errread,errwrite):
if not isinstance(args,types.StringTypes):
args=list2cmdline(args)
if startupinfo is None:
startupinfo=STARTUPINFO()
if None not in(p2cread,c2pwrite,errwrite):
startupinfo.dwFlags|=STARTF_USESTDHANDLES
startupinfo.hStdInput=p2cread
startupinfo.hStdOutput=c2pwrite
startupinfo.hStdError=errwrite
if shell:
startupinfo.dwFlags|=STARTF_USESHOWWINDOW
startupinfo.wShowWindow=SW_HIDE
comspec=os.environ.get("COMSPEC","cmd.exe")
args=comspec+" /c "+args
if(GetVersion()>=0x80000000L or os.path.basename(comspec).lower()=="command.com"):
w9xpopen=self._find_w9xpopen()
args='"%s" %s'%(w9xpopen,args)
creationflags|=CREATE_NEW_CONSOLE
try:
hp,ht,pid,tid=CreateProcess(executable,args,None,None,1,creationflags,env,cwd,startupinfo)
except pywintypes.error,e:
raise WindowsError(*e.args)
self._child_created=True
self._handle=hp
self.pid=pid
ht.Close()
if p2cread is not None:
p2cread.Close()
if c2pwrite is not None:
c2pwrite.Close()
if errwrite is not None:
errwrite.Close()
def poll(self,_deadstate=None):
if self.returncode is None:
if WaitForSingleObject(self._handle,0)==WAIT_OBJECT_0:
self.returncode=GetExitCodeProcess(self._handle)
return self.returncode
def wait(self):
if self.returncode is None:
obj=WaitForSingleObject(self._handle,INFINITE)
self.returncode=GetExitCodeProcess(self._handle)
return self.returncode
def _readerthread(self,fh,buffer):
buffer.append(fh.read())
def _communicate(self,input):
stdout=None
stderr=None
if self.stdout:
stdout=[]
stdout_thread=threading.Thread(target=self._readerthread,args=(self.stdout,stdout))
stdout_thread.setDaemon(True)
stdout_thread.start()
if self.stderr:
stderr=[]
stderr_thread=threading.Thread(target=self._readerthread,args=(self.stderr,stderr))
stderr_thread.setDaemon(True)
stderr_thread.start()
if self.stdin:
if input is not None:
self.stdin.write(input)
self.stdin.close()
if self.stdout:
stdout_thread.join()
if self.stderr:
stderr_thread.join()
if stdout is not None:
stdout=stdout[0]
if stderr is not None:
stderr=stderr[0]
if self.universal_newlines and hasattr(file,'newlines'):
if stdout:
stdout=self._translate_newlines(stdout)
if stderr:
stderr=self._translate_newlines(stderr)
self.wait()
return(stdout,stderr)
else:
def _get_handles(self,stdin,stdout,stderr):
p2cread,p2cwrite=None,None
c2pread,c2pwrite=None,None
errread,errwrite=None,None
if stdin is None:
pass
elif stdin==PIPE:
p2cread,p2cwrite=os.pipe()
elif isinstance(stdin,int):
p2cread=stdin
else:
p2cread=stdin.fileno()
if stdout is None:
pass
elif stdout==PIPE:
c2pread,c2pwrite=os.pipe()
elif isinstance(stdout,int):
c2pwrite=stdout
else:
c2pwrite=stdout.fileno()
if stderr is None:
pass
elif stderr==PIPE:
errread,errwrite=os.pipe()
elif stderr==STDOUT:
errwrite=c2pwrite
elif isinstance(stderr,int):
errwrite=stderr
else:
errwrite=stderr.fileno()
return(p2cread,p2cwrite,c2pread,c2pwrite,errread,errwrite)
def _set_cloexec_flag(self,fd):
try:
cloexec_flag=fcntl.FD_CLOEXEC
except AttributeError:
cloexec_flag=1
old=fcntl.fcntl(fd,fcntl.F_GETFD)
fcntl.fcntl(fd,fcntl.F_SETFD,old|cloexec_flag)
def _close_fds(self,but):
for i in xrange(3,MAXFD):
if i==but:
continue
try:
os.close(i)
except:
pass
def _execute_child(self,args,executable,preexec_fn,close_fds,cwd,env,universal_newlines,startupinfo,creationflags,shell,p2cread,p2cwrite,c2pread,c2pwrite,errread,errwrite):
if isinstance(args,types.StringTypes):
args=[args]
else:
args=list(args)
if shell:
args=["/bin/sh","-c"]+args
if executable is None:
executable=args[0]
errpipe_read,errpipe_write=os.pipe()
self._set_cloexec_flag(errpipe_write)
gc_was_enabled=gc.isenabled()
gc.disable()
try:
self.pid=os.fork()
except:
if gc_was_enabled:
gc.enable()
raise
self._child_created=True
if self.pid==0:
try:
if p2cwrite:
os.close(p2cwrite)
if c2pread:
os.close(c2pread)
if errread:
os.close(errread)
os.close(errpipe_read)
if p2cread:
os.dup2(p2cread,0)
if c2pwrite:
os.dup2(c2pwrite,1)
if errwrite:
os.dup2(errwrite,2)
if p2cread and p2cread not in(0,):
os.close(p2cread)
if c2pwrite and c2pwrite not in(p2cread,1):
os.close(c2pwrite)
if errwrite and errwrite not in(p2cread,c2pwrite,2):
os.close(errwrite)
if close_fds:
self._close_fds(but=errpipe_write)
if cwd is not None:
os.chdir(cwd)
if preexec_fn:
apply(preexec_fn)
if env is None:
os.execvp(executable,args)
else:
os.execvpe(executable,args,env)
except:
exc_type,exc_value,tb=sys.exc_info()
exc_lines=traceback.format_exception(exc_type,exc_value,tb)
exc_value.child_traceback=''.join(exc_lines)
os.write(errpipe_write,pickle.dumps(exc_value))
os._exit(255)
if gc_was_enabled:
gc.enable()
os.close(errpipe_write)
if p2cread and p2cwrite:
os.close(p2cread)
if c2pwrite and c2pread:
os.close(c2pwrite)
if errwrite and errread:
os.close(errwrite)
data=os.read(errpipe_read,1048576)
os.close(errpipe_read)
if data!="":
os.waitpid(self.pid,0)
child_exception=pickle.loads(data)
raise child_exception
def _handle_exitstatus(self,sts):
if os.WIFSIGNALED(sts):
self.returncode=-os.WTERMSIG(sts)
elif os.WIFEXITED(sts):
self.returncode=os.WEXITSTATUS(sts)
else:
raise RuntimeError("Unknown child exit status!")
def poll(self,_deadstate=None):
if self.returncode is None:
try:
pid,sts=os.waitpid(self.pid,os.WNOHANG)
if pid==self.pid:
self._handle_exitstatus(sts)
except os.error:
if _deadstate is not None:
self.returncode=_deadstate
return self.returncode
def wait(self):
if self.returncode is None:
pid,sts=os.waitpid(self.pid,0)
self._handle_exitstatus(sts)
return self.returncode
def _communicate(self,input):
read_set=[]
write_set=[]
stdout=None
stderr=None
if self.stdin:
self.stdin.flush()
if input:
write_set.append(self.stdin)
else:
self.stdin.close()
if self.stdout:
read_set.append(self.stdout)
stdout=[]
if self.stderr:
read_set.append(self.stderr)
stderr=[]
input_offset=0
while read_set or write_set:
rlist,wlist,xlist=select.select(read_set,write_set,[])
if self.stdin in wlist:
bytes_written=os.write(self.stdin.fileno(),buffer(input,input_offset,512))
input_offset+=bytes_written
if input_offset>=len(input):
self.stdin.close()
write_set.remove(self.stdin)
if self.stdout in rlist:
data=os.read(self.stdout.fileno(),1024)
if data=="":
self.stdout.close()
read_set.remove(self.stdout)
stdout.append(data)
if self.stderr in rlist:
data=os.read(self.stderr.fileno(),1024)
if data=="":
self.stderr.close()
read_set.remove(self.stderr)
stderr.append(data)
if stdout is not None:
stdout=''.join(stdout)
if stderr is not None:
stderr=''.join(stderr)
if self.universal_newlines and hasattr(file,'newlines'):
if stdout:
stdout=self._translate_newlines(stdout)
if stderr:
stderr=self._translate_newlines(stderr)
self.wait()
return(stdout,stderr)