269 lines
8.4 KiB
Python
269 lines
8.4 KiB
Python
|
"""
|
||
|
|
||
|
Platform dependent plugin execution helper functions.
|
||
|
|
||
|
"""
|
||
|
|
||
|
import os
|
||
|
import sys
|
||
|
import uuid
|
||
|
|
||
|
|
||
|
__all__ = ["generate_pipename",
|
||
|
"create_pipe",
|
||
|
"validate_plugin",
|
||
|
"launch_plugin",
|
||
|
"connect_pipe",
|
||
|
"write_outconfig",
|
||
|
"close_pipe",
|
||
|
"PipeError"]
|
||
|
|
||
|
|
||
|
CONNECT_TIMEOUT_SECS = 45
|
||
|
|
||
|
class PipeError(Exception):
|
||
|
pass
|
||
|
|
||
|
mswindows = (sys.platform == "win32")
|
||
|
|
||
|
if mswindows:
|
||
|
import win32pipe
|
||
|
import win32file
|
||
|
import pywintypes
|
||
|
import win32event
|
||
|
import subprocess
|
||
|
|
||
|
ERROR_PIPE_CONNECTED = 535
|
||
|
ERROR_IO_PENDING = 997
|
||
|
|
||
|
PIPE_PREFIX = "\\\\.\\pipe\\fb-pipe"
|
||
|
|
||
|
else:
|
||
|
import signal
|
||
|
import subprocess
|
||
|
|
||
|
PIPE_PREFIX = "/tmp/fb-pipe-"
|
||
|
|
||
|
|
||
|
#
|
||
|
# Cross platform functions
|
||
|
#
|
||
|
def generate_pipename():
|
||
|
return PIPE_PREFIX + str(uuid.uuid4())
|
||
|
|
||
|
#
|
||
|
# MS Windows
|
||
|
#
|
||
|
if mswindows:
|
||
|
|
||
|
def create_pipe(pipeName):
|
||
|
# XXX - We should validate here and return None on fail
|
||
|
pipe = win32pipe.CreateNamedPipe(pipeName,
|
||
|
win32pipe.PIPE_ACCESS_INBOUND | win32file.FILE_FLAG_OVERLAPPED,
|
||
|
0x0,
|
||
|
1,
|
||
|
1024,
|
||
|
1024,
|
||
|
0,
|
||
|
None)
|
||
|
return pipe
|
||
|
|
||
|
def validate_plugin(binName, inName, io):
|
||
|
cmdLine = []
|
||
|
if binName.endswith(".py"):
|
||
|
cmdLine.append("python.exe")
|
||
|
cmdLine.append("\"%s\"" % binName)
|
||
|
cmdLine.append("--InConfig \"%s\"" % inName)
|
||
|
cmdLine.append("--ValidateOnly true")
|
||
|
try:
|
||
|
retcode = subprocess.call(" ".join(cmdLine),
|
||
|
stdout=io.stdout,
|
||
|
stderr=io.stdout,
|
||
|
stdin=io.stdin,
|
||
|
env=os.environ)
|
||
|
except OSError, e:
|
||
|
io.print_error("Failed to execute: %s" % str(e))
|
||
|
retcode = 1
|
||
|
|
||
|
return retcode
|
||
|
|
||
|
def launch_plugin(binName, inName, pipeName, logFile, io, newconsole):
|
||
|
"""Execute the process with the passed in parameters. Note that the
|
||
|
output parameter is not a file name, but rather a named pipe!"""
|
||
|
if newconsole:
|
||
|
cmdLine = []
|
||
|
cmdLine.append("start \"%s\" cmd /T:9F /K " % binName)
|
||
|
if binName.endswith(".py"):
|
||
|
cmdLine.append("\"python.exe \"%s\"" % binName)
|
||
|
else:
|
||
|
cmdLine.append("\"\"%s\"" % binName)
|
||
|
cmdLine.append("--InConfig \"%s\"" % inName)
|
||
|
cmdLine.append("--OutConfig \"%s\"" % pipeName)
|
||
|
cmdLine.append("--LogFile \"%s\"\"" % logFile)
|
||
|
p = subprocess.Popen(" ".join(cmdLine), shell=True, env=os.environ)
|
||
|
else:
|
||
|
cmdLine = []
|
||
|
if binName.endswith(".py"):
|
||
|
cmdLine.append("python.exe")
|
||
|
cmdLine.append("\"%s\"" % binName)
|
||
|
cmdLine.append("--InConfig \"%s\"" % inName)
|
||
|
cmdLine.append("--OutConfig \"%s\"" % pipeName)
|
||
|
cmdLine.append("--LogFile \"%s\"" % logFile)
|
||
|
p = subprocess.Popen(" ".join(cmdLine),
|
||
|
shell=False,
|
||
|
stdout=io.stdout,
|
||
|
stderr=io.stderr,
|
||
|
stdin=io.stdin,
|
||
|
env=os.environ)
|
||
|
return p
|
||
|
|
||
|
|
||
|
def connect_pipe(pipe, pipeName):
|
||
|
overLap = pywintypes.OVERLAPPED()
|
||
|
overLap.hEvent = win32event.CreateEvent(None, 1, 0, None)
|
||
|
if overLap.hEvent == 0:
|
||
|
raise PipeError('Could not create hEvent')
|
||
|
|
||
|
try:
|
||
|
# Wait for a pipe client connection
|
||
|
ret = win32pipe.ConnectNamedPipe(pipe, overLap)
|
||
|
if not ret in (0, ERROR_PIPE_CONNECTED):
|
||
|
if ret == ERROR_IO_PENDING:
|
||
|
ret = win32event.WaitForSingleObject(overLap.hEvent,
|
||
|
1000 * CONNECT_TIMEOUT_SECS)
|
||
|
if ret != win32event.WAIT_OBJECT_0:
|
||
|
# Timeout error
|
||
|
raise PipeError('Timeout error')
|
||
|
else:
|
||
|
# API error
|
||
|
raise PipeError('API error')
|
||
|
|
||
|
ret = win32pipe.GetOverlappedResult(pipe, overLap, True)
|
||
|
if not ret in (0, ERROR_PIPE_CONNECTED):
|
||
|
# API Error
|
||
|
raise PipeError('API error 2')
|
||
|
except PipeError:
|
||
|
# Named pipe exception
|
||
|
win32file.CancelIo(pipe)
|
||
|
pipe.close()
|
||
|
raise
|
||
|
except BaseException, err:
|
||
|
win32file.CancelIo(pipe)
|
||
|
pipe.close()
|
||
|
pipe = None
|
||
|
raise PipeError('BaseException : ' + str(err))
|
||
|
|
||
|
return pipe
|
||
|
|
||
|
|
||
|
def write_outconfig(fileName, pipe):
|
||
|
tmpFile = open(fileName, "w")
|
||
|
while 1:
|
||
|
try:
|
||
|
(ret, line) = win32file.ReadFile(pipe, 4096, None)
|
||
|
if ret != 0 or line == "":
|
||
|
break
|
||
|
else:
|
||
|
tmpFile.write(line)
|
||
|
except:
|
||
|
break
|
||
|
tmpFile.close()
|
||
|
|
||
|
|
||
|
def close_pipe(pipe):
|
||
|
win32file.CancelIo(pipe)
|
||
|
pipe.close()
|
||
|
|
||
|
#
|
||
|
# Linux
|
||
|
#
|
||
|
else:
|
||
|
def SIGALRM_handler(sigNum, frame):
|
||
|
return
|
||
|
|
||
|
def create_pipe(pipename):
|
||
|
os.mkfifo(pipename, 0666)
|
||
|
return None
|
||
|
|
||
|
def launch_plugin(binName, inName, pipeName, logFile, io, newconsole):
|
||
|
"""Execute the process with the passed in parameters. Note that the
|
||
|
output parameter is not a file name, but rather a named pipe!"""
|
||
|
if newconsole:
|
||
|
cmdLine = []
|
||
|
cmdLine.append("/usr/bin/xterm -hold -T \"%s\" -e " % binName)
|
||
|
cmdLine.append("\"%s\"" % binName)
|
||
|
cmdLine.append("--InConfig \"%s\"" % inName) # Contains the input parameters
|
||
|
cmdLine.append("--OutConfig \"%s\"" % pipeName)
|
||
|
cmdLine.append("--LogFile \"%s\"" % logFile)
|
||
|
p = subprocess.Popen(" ".join(cmdLine), shell=True, env=os.environ)
|
||
|
else:
|
||
|
cmdLine = []
|
||
|
if binName.endswith(".py"):
|
||
|
cmdLine.append("/usr/bin/python2.6")
|
||
|
cmdLine.append("\"%s\"" % binName)
|
||
|
cmdLine.append("--InConfig \"%s\"" % inName) # Contains the input parameters
|
||
|
cmdLine.append("--OutConfig \"%s\"" % pipeName)
|
||
|
cmdLine.append("--LogFile \"%s\"" % logFile)
|
||
|
p = subprocess.Popen(" ".join(cmdLine), shell=True,
|
||
|
stdout=io.stdout,
|
||
|
stderr=io.stderr,
|
||
|
stdin=io.stdin,
|
||
|
env=os.environ)
|
||
|
return p
|
||
|
|
||
|
def validate_plugin(binName, inName, io):
|
||
|
cmdLine = []
|
||
|
if binName.endswith(".py"):
|
||
|
cmdLine.append("/usr/bin/python2.6")
|
||
|
cmdLine.append("\"%s\"" % binName)
|
||
|
cmdLine.append("--InConfig \"%s\"" % inName)
|
||
|
cmdLine.append("--ValidateOnly true")
|
||
|
try:
|
||
|
retcode = subprocess.call(" ".join(cmdLine),
|
||
|
stdout=io.stdout,
|
||
|
stderr=io.stdout,
|
||
|
stdin=io.stdin,
|
||
|
shell=True,
|
||
|
env=os.environ)
|
||
|
except OSError, e:
|
||
|
io.print_error("Failed to execute: %s" % str(e))
|
||
|
retcode = 1
|
||
|
return retcode
|
||
|
|
||
|
def connect_pipe(pipe, pipeName):
|
||
|
"""
|
||
|
"""
|
||
|
oldHandler = signal.getsignal(signal.SIGALRM)
|
||
|
try:
|
||
|
signal.signal(signal.SIGALRM, SIGALRM_handler)
|
||
|
signal.alarm(CONNECT_TIMEOUT_SECS + 1)
|
||
|
retval = os.open(pipeName, os.O_RDONLY)
|
||
|
signal.alarm(0)
|
||
|
except OSError:
|
||
|
# Alarm Timeout
|
||
|
retval = None
|
||
|
except BaseException:
|
||
|
# Keyboard interrupt
|
||
|
retval = None
|
||
|
|
||
|
# cancel the alarm and restore prev handler
|
||
|
signal.signal(signal.SIGALRM, oldHandler)
|
||
|
|
||
|
return retval
|
||
|
|
||
|
|
||
|
def write_outconfig(fileName, pipe):
|
||
|
tmpFile = open(fileName, "w")
|
||
|
while 1:
|
||
|
line = os.read(pipe, 4096)
|
||
|
if len(line) == 0:
|
||
|
break
|
||
|
else:
|
||
|
tmpFile.write(line)
|
||
|
tmpFile.close()
|
||
|
|
||
|
def close_pipe(pipe):
|
||
|
os.close(pipe)
|
||
|
|
||
|
|