]>
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 #----------------------------------------------------------------------
27 # For environment settings
30 return self
.__dict
__.copy()
32 def write(self
, filename
="config", outfile
=None):
34 f
= file(filename
, "w")
37 for k
, v
in self
.__dict
__.items():
38 f
.write('%s="%s"\n' % (k
, v
))
40 def read(self
, filename
="config"):
41 myfile
= open(filename
, "r")
42 for line
in myfile
.readlines():
44 if len(line
) > 0 and line
[0] == "#":
45 continue # it's a comment, move on
46 data
= line
.split("=")
48 self
.__dict
__[data
[0].strip()] = data
[1].strip()
53 Each Job is a monitor wrapped around an externally executing
54 process. It handles starting the process, polling if it is still
55 running, reading and logging it's output, and killing it if
61 def __init__(self
, label
, command
, args
=[], env
=os
.environ
):
63 self
.command
= command
68 if not os
.path
.exists(self
.LOGBASE
):
69 os
.makedirs(self
.LOGBASE
)
70 self
.log
= file("%s/%s.log" % (self
.LOGBASE
, label
), "w", 0)
73 self
.proc
= Popen([self
.command
] + self
.args
, # the command and args to execute
74 stdout
=PIPE
, stderr
=STDOUT
, env
=self
.env
,
75 bufsize
=0 # line-buffered
77 # put the file in non-blocking mode
78 #flags = fcntl.fcntl (self.proc.stdout, fcntl.F_GETFL, 0)
79 #flags = flags | os.O_NONBLOCK
80 #fcntl.fcntl (self.proc.stdout, fcntl.F_SETFL, flags)
84 if self
.proc
is not None and self
.proc
.returncode
is None:
85 os
.kill(self
.proc
.pid
, signal
.SIGTERM
)
90 if self
.proc
is not None:
91 return self
.proc
.stdout
.fileno()
97 if self
.proc
is not None:
98 while self
.linesAvailable():
99 line
= self
.proc
.stdout
.readline()
103 line
= "** %s: %s" % (self
.label
, line
)
104 sys
.stdout
.write(line
)
107 def linesAvailable(self
):
108 if self
.proc
is None:
110 ind
, outd
, err
= select
.select([self
], [], [], 0)
118 if self
.proc
is None:# or self.linesAvailable():
120 return self
.proc
.poll() is not None
124 if self
.proc
is None: return None
125 return self
.proc
.wait()
129 if self
.proc
is None: return None
130 return self
.proc
.poll()
133 def returnCode(self
):
134 if self
.proc
is None: return None
135 return self
.proc
.returncode
138 #----------------------------------------------------------------------
142 This class helps manage the running of a Task, which is a simply a
143 sequence of one or more Jobs, where subesquent jobs are not
144 started until prior ones are completed.
146 def __init__(self
, jobs
=[]):
147 if type(jobs
) != list:
152 def append(self
, job
):
153 self
.jobs
.append(job
)
156 if self
.active
> len(self
.jobs
)-1:
159 return self
.jobs
[self
.active
]
163 if self
.active
< len(self
.jobs
):
164 self
.jobs
[self
.active
].start()
166 #----------------------------------------------------------------------
168 class TaskRunner(object):
170 Manages the running of multiple tasks.
172 def __init__(self
, tasks
=[]):
173 if type(tasks
) != list:
175 self
.tasks
= tasks
[:]
177 def append(self
, task
):
178 self
.tasks
.append(task
)
181 # start all the active jobs
182 for task
in self
.tasks
:
183 task
.activeJob().start()
186 # loop, getting output from the jobs, etc.
188 # get all active Jobs
189 jobs
= [t
.activeJob() for t
in self
.tasks
if t
.activeJob()]
193 # wait for a job to have output ready, then log it
194 input, output
, err
= select
.select(jobs
, [], [], 1)
198 # check for finished jobs
199 for task
in self
.tasks
:
200 job
= task
.activeJob()
201 if job
and job
.finished():
202 if job
.returnCode() != 0:
203 rc
= job
.returnCode()
204 print "JOB RETURNED FAILURE CODE! (%d)" % rc
209 except KeyboardInterrupt:
210 print "STOPPING JOBS..."
215 print "Unknown exception..."
222 def stopAllJobs(self
):
223 for task
in self
.tasks
:
224 job
= task
.activeJob()
228 #----------------------------------------------------------------------
231 if __name__
== "__main__":
233 j1
= Job("label1", ["./tmp/job-1.py", "TEST-1"])
234 j2
= Job("label2", ["./tmp/job-2.sh", "TEST-2"])
240 j3
= Job("task2a", ["./tmp/job-1.py", "TASK-2a"])
241 j4
= Job("task2b", ["./tmp/job-2.sh", "TASK-2b"])
247 t3
= Task([Job("error", ["./tmp/job-3.sh", "TASK-3"])])
254 for task
in tr
.tasks
:
255 for job
in task
.jobs
: