1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import string, os.path, time, thread, logging, Queue
21
22 from pysys import log
23 from pysys import process_lock
24 from pysys.constants import *
25 from pysys.exceptions import *
26
27
28 EXPR = re.compile(".*\n$")
29
31 """ Converts a unicode string or a utf-8 bit string into a unicode string.
32
33 """
34 if isinstance(s, unicode):
35 return s
36 else:
37 return unicode(s, "utf8")
38
40 """Abstract base process wrapper class for process execution and management.
41
42 A base implementation of common process related operations, which should be extended
43 by the OS specific wrapper classes.
44
45 @ivar pid: The process id for a running or complete process (as set by the OS)
46 @type pid: integer
47 @ivar exitStatus: The process exit status for a completed process
48 @type exitStatus: integer
49
50 """
51
52 - def __init__(self, command, arguments, environs, workingDir, state, timeout, stdout=None, stderr=None, displayName=None):
53 """Create an instance of the process wrapper.
54
55 @param command: The full path to the command to execute
56 @param arguments: A list of arguments to the command
57 @param environs: A dictionary of environment variables (key, value) for the process context execution
58 @param workingDir: The working directory for the process
59 @param state: The state of the process (L{pysys.constants.FOREGROUND} or L{pysys.constants.BACKGROUND}
60 @param timeout: The timeout in seconds to be applied to the process
61 @param stdout: The full path to the filename to write the stdout of the process
62 @param stderr: The full path to the filename to write the sdterr of the process
63 @param displayName: Display name for this process
64
65 """
66 self.displayName = displayName if displayName else os.path.basename(command)
67 self.command = command
68 self.arguments = arguments
69 self.environs = {}
70 for key in environs: self.environs[_stringToUnicode(key)] = _stringToUnicode(environs[key])
71 self.workingDir = workingDir
72 self.state = state
73 self.timeout = timeout
74
75
76 self.pid = None
77 self.exitStatus = None
78
79
80 log.debug("Process parameters for executable %s" % os.path.basename(self.command))
81 log.debug(" command : %s", self.command)
82 for a in self.arguments: log.debug(" argument : %s", a)
83 log.debug(" working dir : %s", self.workingDir)
84 log.debug(" stdout : %s", stdout)
85 log.debug(" stderr : %s", stderr)
86 keys=self.environs.keys()
87 keys.sort()
88 for e in keys: log.debug(" environment : %s=%s", e, self.environs[e])
89
90
91 self._outQueue = None
92
93
94 - def __str__(self): return self.displayName
95 - def __repr__(self): return '%s (pid %s)'%(self.displayName, self.pid)
96
97
100 - def writeStdin(self): raise Exception('Not implemented')
101 - def stop(self): raise Exception('Not implemented')
102 - def signal(self): raise Exception('Not implemented')
103
104 - def write(self, data, addNewLine=True):
105 """Write data to the stdin of the process.
106
107 Note that when the addNewLine argument is set to true, if a new line does not
108 terminate the input data string, a newline character will be added. If one
109 already exists a new line character will not be added. Should you explicitly
110 require to add data without the method appending a new line charater set
111 addNewLine to false.
112
113 @param data: The data to write to the process stdout
114 @param addNewLine: True if a new line character is to be added to the end of
115 the data string
116
117 """
118 if not self.running(): raise Exception('Cannot write to process stdin when it is not running')
119 if addNewLine and not EXPR.search(data): data = "%s\n" % data
120
121 if self._outQueue == None:
122
123 self._outQueue = Queue.Queue()
124 thread.start_new_thread(self.writeStdin, ())
125
126 self._outQueue.put(data)
127
129 """Check to see if a process is running, returning true if running.
130
131 @return: The running status (True / False)
132 @rtype: integer
133
134 """
135 return self.setExitStatus() is None
136
137
138 - def wait(self, timeout):
139 """Wait for a process to complete execution.
140
141 The method will block until either the process is no longer running, or the timeout
142 is exceeded. Note that the method will not terminate the process if the timeout is
143 exceeded.
144
145 @param timeout: The timeout to wait in seconds. Always provide a
146 timeout, otherwise your test may block indefinitely!
147 @raise ProcessTimeout: Raised if the timeout is exceeded.
148
149 """
150 startTime = time.time()
151 while self.running():
152 if timeout:
153 currentTime = time.time()
154 if currentTime > startTime + timeout:
155 raise ProcessTimeout, "Process timedout"
156 time.sleep(0.05)
157
158
159
161 """Start a process using the runtime parameters set at instantiation.
162
163 @raise ProcessError: Raised if there is an error creating the process
164 @raise ProcessTimeout: Raised in the process timed out (foreground process only)
165
166 """
167 self._outQueue = None
168
169 if self.workingDir and not os.path.isdir(self.workingDir):
170 raise Exception('Cannot start process %s as workingDir "%s" does not exist'% (self, self.workingDir))
171
172 if self.state == FOREGROUND:
173 self.startBackgroundProcess()
174 self.wait(self.timeout)
175 else:
176 self.startBackgroundProcess()
177