]>
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
: