root/fizzjik/fizzjik/process.py

Revision 87, 3.4 kB (checked in by devja..@anarkystic.com, 1 month ago)

added a lot more interactiveness to the process bits

Line 
1 # vim: softtabstop=4 shiftwidth=4
2 import os
3 import logging
4
5 from twisted.application import service
6 from twisted.internet import protocol, reactor, defer
7 from twisted.internet import error
8
9
10 #from fizzjik.interfaces import IOutput, implements
11 from fizzjik.config import ConfigurableMixin, if_config
12
13 class ProcessProtocol(protocol.ProcessProtocol):
14     posix_exec = '/usr/bin/env'
15     posix_args = ['/usr/bin/env']
16
17     running = False
18     outCallback = None
19     errCallback = None
20     outDeferred = None
21     errDeferred = None
22     startedDeferred = None
23     endedDeferred = None
24     out = None
25     err = None
26
27     def __init__(self, platform="posix", outCallback=None, errCallback=None):
28         self.platform = platform
29         self.outDeferred = defer.Deferred()
30         self.errDeferred = defer.Deferred()
31         self.startedDeferred = defer.Deferred()
32         self.endedDeferred = defer.Deferred()
33        
34
35         self.endedDeferred.addErrback(self._handleCleanExit)
36         self.endedDeferred.addErrback(self._handleUncleanExit)
37
38         if not outCallback:
39             outCallback = self.defaultOut
40         self.outCallback = outCallback
41
42         if not errCallback:
43             errCallback = self.defaultErr
44         self.errCallback = errCallback
45        
46         self.err = []
47         self.out = []
48
49
50
51     def connectionMade(self):
52         self.running = True
53         self.startedDeferred.callback(True)
54         logging.debug("process started...")
55
56     def spawn(self, *args):
57         if not self.getExec():
58             return
59         reactor.spawnProcess(self, self.getExec(), args=self.getArgs()+list(args), env=os.environ)
60         return self.startedDeferred
61
62     def kill(self):
63         if self.running:
64             self.transport.signalProcess('KILL')
65
66     def processEnded(self, reason):
67         if not self.running:
68             self.startedDeferred.errback(reason)
69         self.endedDeferred.callback(reason)
70         self.outDeferred.callback(self.out)
71         self.errDeferred.callback(self.err)
72         self.running = False
73
74     def _handleCleanExit(self, reason):
75         if not isinstance(reason.value, error.ProcessDone):
76             return reason
77         if reason.value.exitCode == 0:
78             logging.debug('process ended cleanly')
79             return True
80         return reason
81
82     def _handleUncleanExit(self, reason):
83         logging.debug('process ended uncleanly: %s' % reason)
84    
85     def outReceived(self, line):
86         for l in line.splitlines():
87             self.out.append(l)
88         self.outCallback(line)
89    
90     def errReceived(self, l):
91         for l in line.splitlines():
92             self.err.append(l)
93         self.errCallback(line)
94
95     @staticmethod
96     def defaultErr(line):
97         logging.debug("\n".join(["err !! %s"%(x) for x in line.splitlines()]))
98    
99     @staticmethod
100     def defaultOut(line):
101         logging.debug("\n".join(["out >> %s"%(x) for x in line.splitlines()]))
102
103     def getExec(self):
104         return getattr(self, '%s_exec'%(self.platform), None)
105    
106     def getArgs(self):
107         return getattr(self, '%s_args'%(self.platform), None)
108
109
110 class ProcessService(service.Service, ConfigurableMixin):
111     enabled = True
112     platform = "posix"
113     protocol = ProcessProtocol
114
115
116     @if_config('enabled')
117     def startService(self):
118         self.process = self.protocol(self.platform)
119         pass
120    
121     @if_config('enabled')
122     def stopService(self):
123         self.process.kill()
124         pass
125    
126     def spawn(self, *args):
127         self.process.spawn(*args)
128
Note: See TracBrowser for help on using the browser.