]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/distrib/all/taskrunner.py
1 #----------------------------------------------------------------------
3 # Purpose: Classes that can manage running of external processes,
4 # either consecutively, simultaneously, or both, and can
5 # log the output of those jobs
11 # Copyright: (c) 2004 by Total Control Software
12 # Licence: wxWindows license
13 #----------------------------------------------------------------------
20 from subprocess
import Popen
, PIPE
, STDOUT
23 __all__
= ["Job", "Task", "TaskRunner"]
25 #----------------------------------------------------------------------
30 Each Job is a monitor wrapped around an externally executing
31 process. It handles starting the process, polling if it is still
32 running, reading and logging it's output, and killing it if
38 def __init__(self
, label
, args
):
43 self
.log
= file("%s/%s.log" % (self
.LOGBASE
, label
), "w", 0)
46 self
.proc
= Popen(self
.args
, # the command and args to execute
47 stdout
=PIPE
, stderr
=STDOUT
,
48 bufsize
=0, # line-buffered
50 # put the file in non-blocking mode
51 #flags = fcntl.fcntl (self.proc.stdout, fcntl.F_GETFL, 0)
52 #flags = flags | os.O_NONBLOCK
53 #fcntl.fcntl (self.proc.stdout, fcntl.F_SETFL, flags)
57 if self
.proc
is not None and self
.proc
.returncode
is None:
58 os
.kill(self
.proc
.pid
, signal
.SIGTERM
)
63 if self
.proc
is not None:
64 return self
.proc
.stdout
.fileno()
70 if self
.proc
is not None:
71 while self
.linesAvailable():
72 line
= self
.proc
.stdout
.readline()
76 line
= "** %s: %s" % (self
.label
, line
)
77 sys
.stdout
.write(line
)
80 def linesAvailable(self
):
83 ind
, outd
, err
= select
.select([self
], [], [], 0)
91 if self
.proc
is None:# or self.linesAvailable():
93 return self
.proc
.poll() is not None
97 if self
.proc
is None: return None
98 return self
.proc
.wait()
102 if self
.proc
is None: return None
103 return self
.proc
.poll()
106 def returnCode(self
):
107 if self
.proc
is None: return None
108 return self
.proc
.returncode
111 #----------------------------------------------------------------------
115 This class helps manage the running of a Task, which is a simply a
116 sequence of one or more Jobs, where subesquent jobs are not
117 started until prior ones are completed.
119 def __init__(self
, jobs
=[]):
120 if type(jobs
) != list:
125 def append(self
, job
):
126 self
.jobs
.append(job
)
129 if self
.active
> len(self
.jobs
)-1:
132 return self
.jobs
[self
.active
]
136 if self
.active
< len(self
.jobs
):
137 self
.jobs
[self
.active
].start()
139 #----------------------------------------------------------------------
141 class TaskRunner(object):
143 Manages the running of multiple tasks.
145 def __init__(self
, tasks
=[]):
146 if type(tasks
) != list:
148 self
.tasks
= tasks
[:]
150 def append(self
, task
):
151 self
.tasks
.append(task
)
154 # start all the active jobs
155 for task
in self
.tasks
:
156 task
.activeJob().start()
159 # loop, getting output from the jobs, etc.
161 # get all active Jobs
162 jobs
= [t
.activeJob() for t
in self
.tasks
if t
.activeJob()]
166 # wait for a job to have output ready, then log it
167 input, output
, err
= select
.select(jobs
, [], [], 1)
171 # check for finished jobs
172 for task
in self
.tasks
:
173 job
= task
.activeJob()
174 if job
and job
.finished():
175 if job
.returnCode() != 0:
176 rc
= job
.returnCode()
177 print "JOB RETURNED FAILURE CODE! (%d)" % rc
182 except KeyboardInterrupt:
183 print "STOPPING JOBS..."
188 print "Unknown exception..."
195 def stopAllJobs(self
):
196 for task
in self
.tasks
:
197 job
= task
.activeJob()
201 #----------------------------------------------------------------------
204 if __name__
== "__main__":
206 j1
= Job("label1", ["./tmp/job-1.py", "TEST-1"])
207 j2
= Job("label2", ["./tmp/job-2.sh", "TEST-2"])
213 j3
= Job("task2a", ["./tmp/job-1.py", "TASK-2a"])
214 j4
= Job("task2b", ["./tmp/job-2.sh", "TASK-2b"])
220 t3
= Task([Job("error", ["./tmp/job-3.sh", "TASK-3"])])
227 for task
in tr
.tasks
:
228 for job
in task
.jobs
: