source: trunk/lang/python/Rappture/tools.py @ 3831

Last change on this file since 3831 was 3831, checked in by clarksm, 11 years ago

Patch to prevent exit when getCommandOutput is used in a thread.
Signals can be handled only in the main thread.

File size: 4.1 KB
Line 
1# ----------------------------------------------------------------------
2#
3# ======================================================================
4#  AUTHOR:  Derrick S. Kearney, Purdue University
5#  AUTHOR:  Steve Clark, Purdue University
6#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
7# ======================================================================
8
9import sys
10import os
11import re
12import subprocess
13import shlex
14import select
15import signal
16import traceback
17
18commandPid = 0
19
20def sig_handler(signalType, frame):
21    global commandPid
22    if commandPid:
23        os.kill(commandPid,signal.SIGTERM)
24
25
26def getCommandOutput(command,
27                     streamOutput=False):
28    global commandPid
29
30    try:
31       sig_INT_handler = signal.signal(signal.SIGINT,sig_handler)
32       sig_HUP_handler = signal.signal(signal.SIGHUP,sig_handler)
33       sig_TERM_handler = signal.signal(signal.SIGTERM,sig_handler)
34    except ValueError:
35#      happens when used in a thread
36       pass
37    except:
38       print traceback.format_exc()
39
40    BUFSIZ = 4096
41    if isinstance(command,list):
42       child = subprocess.Popen(command,bufsize=BUFSIZ, \
43                                stdout=subprocess.PIPE, \
44                                stderr=subprocess.PIPE, \
45                                close_fds=True)
46    else:
47       try:
48          commandStr = str(command)
49       except UnicodeEncodeError:
50          commandStr = unicode(command).encode('unicode_escape')
51       commandArgs = shlex.split(commandStr)
52       child = subprocess.Popen(commandArgs,bufsize=BUFSIZ, \
53                                stdout=subprocess.PIPE, \
54                                stderr=subprocess.PIPE, \
55                                close_fds=True)
56    commandPid = child.pid
57    childout   = child.stdout
58    childoutFd = childout.fileno()
59    childerr   = child.stderr
60    childerrFd = childerr.fileno()
61
62    outEOF = False
63    errEOF = False
64
65    outData = []
66    errData = []
67
68    while True:
69        toCheck = []
70        if not outEOF:
71            toCheck.append(childoutFd)
72        if not errEOF:
73            toCheck.append(childerrFd)
74        try:
75            readyRead,readyWrite,readyException = select.select(toCheck,[],[]) # wait for input
76        except select.error,err:
77            readyRead = []
78            readyWrite = []
79            readyException = []
80        if childoutFd in readyRead:
81            outChunk = os.read(childoutFd,BUFSIZ)
82            if outChunk == '':
83                outEOF = True
84            outData.append(outChunk)
85            if streamOutput:
86                sys.stdout.write(outChunk)
87                sys.stdout.flush()
88
89        if childerrFd in readyRead:
90            errChunk = os.read(childerrFd,BUFSIZ)
91            if errChunk == '':
92                errEOF = True
93            errData.append(errChunk)
94            if streamOutput:
95                sys.stderr.write(errChunk)
96                sys.stderr.flush()
97
98        if outEOF and errEOF:
99            break
100
101    pid,err = os.waitpid(commandPid,0)
102    commandPid = 0
103
104    try:
105       signal.signal(signal.SIGINT,sig_INT_handler)
106       signal.signal(signal.SIGHUP,sig_HUP_handler)
107       signal.signal(signal.SIGTERM,sig_TERM_handler)
108    except UnboundLocalError:
109#      happens when used in a thread
110       pass
111    except:
112       print traceback.format_exc()
113
114    if err != 0:
115        if   os.WIFSIGNALED(err):
116           sys.stderr.write("%s failed w/ signal %d\n" % (command,os.WTERMSIG(err)))
117        else:
118           if os.WIFEXITED(err):
119               err = os.WEXITSTATUS(err)
120           sys.stderr.write("%s failed w/ exit code %d\n" % (command,err))
121        if not streamOutput:
122           sys.stderr.write("%s\n" % ("".join(errData)))
123
124    return err,"".join(outData),"".join(errData)
125
126
127def getDriverNumber(driverFileName):
128    driverNumRslt = re.search(r'[0-9]+',os.path.split(driverFileName)[1])
129    if driverNumRslt == None:
130        return None
131    return driverNumRslt.group()
132
133
134def writeFile(fileName,text):
135    file_object = open(fileName, "w")
136    if file_object:
137        file_object.write(text)
138        file_object.close()
139    else:
140        raise RuntimeError, 'could not open %s for writing' % (fileName)
141
Note: See TracBrowser for help on using the repository browser.