Merge lp:~mterry/duplicity/drop-pexpect into lp:duplicity/0.6
- drop-pexpect
- Merge into 0.6-series
Status: | Merged |
---|---|
Merged at revision: | 974 |
Proposed branch: | lp:~mterry/duplicity/drop-pexpect |
Merge into: | lp:duplicity/0.6 |
Prerequisite: | lp:~mterry/duplicity/fix-drop-u1 |
Diff against target: |
2000 lines (+13/-1853) 8 files modified
bin/duplicity.1 (+3/-0) duplicity/backends/_ssh_pexpect.py (+2/-1) duplicity/backends/~par2wrapperbackend.py (+5/-4) duplicity/pexpect.py (+0/-1845) po/POTFILES.in (+0/-1) setup.py (+1/-1) testing/helpers/helper.py (+1/-1) tox.ini (+1/-0) |
To merge this branch: | bzr merge lp:~mterry/duplicity/drop-pexpect |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
duplicity-team | Pending | ||
Review via email: mp+216389@code.launchpad.net |
This proposal supersedes a proposal from 2014-04-17.
Commit message
Description of the change
Drop our local copy of pexpect in favor of a system version.
It's only used by the pexpect ssh backend (and if you're opting into that, you probably can expect that you will need pexpect) and the tests.
I've done a quick smoketest (backed up and restored using --ssh-backend=
- 975. By Michael Terry
-
fix typo
edso (ed.so) wrote : | # |
Michael Terry (mterry) wrote : | # |
Yes, it works, at least in a simple par2+file:/// test.
On 17 April 2014 16:52, edso <email address hidden> wrote:
> Mike,
>
> could you please check if the par backend still works, as it seems to be
> affected as well?
>
> thx.. ede
> --
> https:/
> Your team duplicity-team is requested to review the proposed merge of
> lp:~mterry/duplicity/drop-pexpect into lp:duplicity.
>
> _______
> Mailing list: https:/
> Post to : <email address hidden>
> Unsubscribe : https:/
> More help : https:/
>
Preview Diff
1 | === modified file 'bin/duplicity.1' |
2 | --- bin/duplicity.1 2014-04-17 17:58:17 +0000 |
3 | +++ bin/duplicity.1 2014-04-17 19:53:39 +0000 |
4 | @@ -120,6 +120,9 @@ |
5 | .B ssh pexpect backend |
6 | .B sftp/scp client binaries |
7 | OpenSSH - http://www.openssh.com/ |
8 | +.br |
9 | +.B Python pexpect module |
10 | +- http://pexpect.sourceforge.net/pexpect.html |
11 | .TP |
12 | .BR "swift backend (OpenStack Object Storage)" |
13 | .B Python swiftclient module |
14 | |
15 | === modified file 'duplicity/backends/_ssh_pexpect.py' |
16 | --- duplicity/backends/_ssh_pexpect.py 2013-12-27 06:39:00 +0000 |
17 | +++ duplicity/backends/_ssh_pexpect.py 2014-04-17 19:53:39 +0000 |
18 | @@ -32,7 +32,6 @@ |
19 | import duplicity.backend |
20 | from duplicity import globals |
21 | from duplicity import log |
22 | -from duplicity import pexpect |
23 | from duplicity.errors import * #@UnusedWildImport |
24 | |
25 | class SSHPExpectBackend(duplicity.backend.Backend): |
26 | @@ -76,6 +75,7 @@ |
27 | |
28 | def run_scp_command(self, commandline): |
29 | """ Run an scp command, responding to password prompts """ |
30 | + import pexpect |
31 | for n in range(1, globals.num_retries+1): |
32 | if n > 1: |
33 | # sleep before retry |
34 | @@ -147,6 +147,7 @@ |
35 | |
36 | def run_sftp_command(self, commandline, commands): |
37 | """ Run an sftp command, responding to password prompts, passing commands from list """ |
38 | + import pexpect |
39 | maxread = 2000 # expected read buffer size |
40 | responses = [pexpect.EOF, |
41 | "(?i)timeout, server not responding", |
42 | |
43 | === modified file 'duplicity/backends/~par2wrapperbackend.py' |
44 | --- duplicity/backends/~par2wrapperbackend.py 2014-02-09 21:42:18 +0000 |
45 | +++ duplicity/backends/~par2wrapperbackend.py 2014-04-17 19:53:39 +0000 |
46 | @@ -20,7 +20,6 @@ |
47 | import re |
48 | from duplicity import backend |
49 | from duplicity.errors import UnsupportedBackendScheme, BackendException |
50 | -from duplicity.pexpect import run |
51 | from duplicity import log |
52 | from duplicity import globals |
53 | |
54 | @@ -52,6 +51,7 @@ |
55 | temp-filename later on. So first of all create a tempdir and symlink |
56 | the soure_path with remote_filename into this. |
57 | """ |
58 | + import pexpect |
59 | if remote_filename is None: |
60 | remote_filename = source_path.get_filename() |
61 | |
62 | @@ -63,7 +63,7 @@ |
63 | |
64 | log.Info("Create Par2 recovery files") |
65 | par2create = 'par2 c -r%d -n1 -q -q %s' % (self.redundancy, source_symlink.get_canonical()) |
66 | - out, returncode = run(par2create, -1, True) |
67 | + out, returncode = pexpect.run(par2create, -1, True) |
68 | source_symlink.delete() |
69 | files_to_transfer = [] |
70 | if not returncode: |
71 | @@ -89,6 +89,7 @@ |
72 | If "par2 verify" detect an error transfer the Par2-volumes into the |
73 | temp-dir and try to repair. |
74 | """ |
75 | + import pexpect |
76 | par2temp = local_path.get_temp_in_same_dir() |
77 | par2temp.mkdir() |
78 | local_path_temp = par2temp.append(remote_filename) |
79 | @@ -100,7 +101,7 @@ |
80 | self.wrapped_backend.get(par2file.get_filename(), par2file) |
81 | |
82 | par2verify = 'par2 v -q -q %s %s' % (par2file.get_canonical(), local_path_temp.get_canonical()) |
83 | - out, returncode = run(par2verify, -1, True) |
84 | + out, returncode = pexpect.run(par2verify, -1, True) |
85 | |
86 | if returncode: |
87 | log.Warn("File is corrupt. Try to repair %s" % remote_filename) |
88 | @@ -111,7 +112,7 @@ |
89 | self.wrapped_backend.get(filename, file) |
90 | |
91 | par2repair = 'par2 r -q -q %s %s' % (par2file.get_canonical(), local_path_temp.get_canonical()) |
92 | - out, returncode = run(par2repair, -1, True) |
93 | + out, returncode = pexpect.run(par2repair, -1, True) |
94 | |
95 | if returncode: |
96 | log.Error("Failed to repair %s" % remote_filename) |
97 | |
98 | === removed file 'duplicity/pexpect.py' |
99 | --- duplicity/pexpect.py 2012-03-13 20:54:44 +0000 |
100 | +++ duplicity/pexpect.py 1970-01-01 00:00:00 +0000 |
101 | @@ -1,1845 +0,0 @@ |
102 | -"""Pexpect is a Python module for spawning child applications and controlling |
103 | -them automatically. Pexpect can be used for automating interactive applications |
104 | -such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup |
105 | -scripts for duplicating software package installations on different servers. It |
106 | -can be used for automated software testing. Pexpect is in the spirit of Don |
107 | -Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python |
108 | -require TCL and Expect or require C extensions to be compiled. Pexpect does not |
109 | -use C, Expect, or TCL extensions. It should work on any platform that supports |
110 | -the standard Python pty module. The Pexpect interface focuses on ease of use so |
111 | -that simple tasks are easy. |
112 | - |
113 | -There are two main interfaces to Pexpect -- the function, run() and the class, |
114 | -spawn. You can call the run() function to execute a command and return the |
115 | -output. This is a handy replacement for os.system(). |
116 | - |
117 | -For example:: |
118 | - |
119 | - pexpect.run('ls -la') |
120 | - |
121 | -The more powerful interface is the spawn class. You can use this to spawn an |
122 | -external child command and then interact with the child by sending lines and |
123 | -expecting responses. |
124 | - |
125 | -For example:: |
126 | - |
127 | - child = pexpect.spawn('scp foo myname@host.example.com:.') |
128 | - child.expect ('Password:') |
129 | - child.sendline (mypassword) |
130 | - |
131 | -This works even for commands that ask for passwords or other input outside of |
132 | -the normal stdio streams. |
133 | - |
134 | -Credits: Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett, |
135 | -Robert Stone, Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids |
136 | -vander Molen, George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin, |
137 | -Geoffrey Marshall, Francisco Lourenco, Glen Mabey, Karthik Gurusamy, Fernando |
138 | -Perez, Corey Minyard, Jon Cohen, Guillaume Chazarain, Andrew Ryan, Nick |
139 | -Craig-Wood, Andrew Stone, Jorgen Grahn (Let me know if I forgot anyone.) |
140 | - |
141 | -Free, open source, and all that good stuff. |
142 | - |
143 | -Permission is hereby granted, free of charge, to any person obtaining a copy of |
144 | -this software and associated documentation files (the "Software"), to deal in |
145 | -the Software without restriction, including without limitation the rights to |
146 | -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
147 | -of the Software, and to permit persons to whom the Software is furnished to do |
148 | -so, subject to the following conditions: |
149 | - |
150 | -The above copyright notice and this permission notice shall be included in all |
151 | -copies or substantial portions of the Software. |
152 | - |
153 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
154 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
155 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
156 | -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
157 | -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
158 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
159 | -SOFTWARE. |
160 | - |
161 | -Pexpect Copyright (c) 2008 Noah Spurrier |
162 | -http://pexpect.sourceforge.net/ |
163 | - |
164 | -$Id: pexpect.py,v 1.1 2009/01/06 22:11:37 loafman Exp $ |
165 | -""" |
166 | - |
167 | -try: |
168 | - import os, sys, time |
169 | - import select |
170 | - import string |
171 | - import re |
172 | - import struct |
173 | - import resource |
174 | - import types |
175 | - import pty |
176 | - import tty |
177 | - import termios |
178 | - import fcntl |
179 | - import errno |
180 | - import traceback |
181 | - import signal |
182 | -except ImportError, e: |
183 | - raise ImportError (str(e) + """ |
184 | - |
185 | -A critical module was not found. Probably this operating system does not |
186 | -support it. Pexpect is intended for UNIX-like operating systems.""") |
187 | - |
188 | -__version__ = '2.3' |
189 | -__revision__ = '$Revision: 1.1 $' |
190 | -__all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'run', 'which', |
191 | - 'split_command_line', '__version__', '__revision__'] |
192 | - |
193 | -# Exception classes used by this module. |
194 | -class ExceptionPexpect(Exception): |
195 | - |
196 | - """Base class for all exceptions raised by this module. |
197 | - """ |
198 | - |
199 | - def __init__(self, value): |
200 | - |
201 | - self.value = value |
202 | - |
203 | - def __str__(self): |
204 | - |
205 | - return str(self.value) |
206 | - |
207 | - def get_trace(self): |
208 | - |
209 | - """This returns an abbreviated stack trace with lines that only concern |
210 | - the caller. In other words, the stack trace inside the Pexpect module |
211 | - is not included. """ |
212 | - |
213 | - tblist = traceback.extract_tb(sys.exc_info()[2]) |
214 | - #tblist = filter(self.__filter_not_pexpect, tblist) |
215 | - tblist = [item for item in tblist if self.__filter_not_pexpect(item)] |
216 | - tblist = traceback.format_list(tblist) |
217 | - return ''.join(tblist) |
218 | - |
219 | - def __filter_not_pexpect(self, trace_list_item): |
220 | - |
221 | - """This returns True if list item 0 the string 'pexpect.py' in it. """ |
222 | - |
223 | - if trace_list_item[0].find('pexpect.py') == -1: |
224 | - return True |
225 | - else: |
226 | - return False |
227 | - |
228 | -class EOF(ExceptionPexpect): |
229 | - |
230 | - """Raised when EOF is read from a child. This usually means the child has exited.""" |
231 | - |
232 | -class TIMEOUT(ExceptionPexpect): |
233 | - |
234 | - """Raised when a read time exceeds the timeout. """ |
235 | - |
236 | -##class TIMEOUT_PATTERN(TIMEOUT): |
237 | -## """Raised when the pattern match time exceeds the timeout. |
238 | -## This is different than a read TIMEOUT because the child process may |
239 | -## give output, thus never give a TIMEOUT, but the output |
240 | -## may never match a pattern. |
241 | -## """ |
242 | -##class MAXBUFFER(ExceptionPexpect): |
243 | -## """Raised when a scan buffer fills before matching an expected pattern.""" |
244 | - |
245 | -def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None): |
246 | - |
247 | - """ |
248 | - This function runs the given command; waits for it to finish; then |
249 | - returns all output as a string. STDERR is included in output. If the full |
250 | - path to the command is not given then the path is searched. |
251 | - |
252 | - Note that lines are terminated by CR/LF (\\r\\n) combination even on |
253 | - UNIX-like systems because this is the standard for pseudo ttys. If you set |
254 | - 'withexitstatus' to true, then run will return a tuple of (command_output, |
255 | - exitstatus). If 'withexitstatus' is false then this returns just |
256 | - command_output. |
257 | - |
258 | - The run() function can often be used instead of creating a spawn instance. |
259 | - For example, the following code uses spawn:: |
260 | - |
261 | - from pexpect import * #@UnusedWildImport |
262 | - child = spawn('scp foo myname@host.example.com:.') |
263 | - child.expect ('(?i)password') |
264 | - child.sendline (mypassword) |
265 | - |
266 | - The previous code can be replace with the following:: |
267 | - |
268 | - from pexpect import * #@UnusedWildImport |
269 | - run ('scp foo myname@host.example.com:.', events={'(?i)password': mypassword}) |
270 | - |
271 | - Examples |
272 | - ======== |
273 | - |
274 | - Start the apache daemon on the local machine:: |
275 | - |
276 | - from pexpect import * #@UnusedWildImport |
277 | - run ("/usr/local/apache/bin/apachectl start") |
278 | - |
279 | - Check in a file using SVN:: |
280 | - |
281 | - from pexpect import * #@UnusedWildImport |
282 | - run ("svn ci -m 'automatic commit' my_file.py") |
283 | - |
284 | - Run a command and capture exit status:: |
285 | - |
286 | - from pexpect import * #@UnusedWildImport |
287 | - (command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1) |
288 | - |
289 | - Tricky Examples |
290 | - =============== |
291 | - |
292 | - The following will run SSH and execute 'ls -l' on the remote machine. The |
293 | - password 'secret' will be sent if the '(?i)password' pattern is ever seen:: |
294 | - |
295 | - run ("ssh username@machine.example.com 'ls -l'", events={'(?i)password':'secret\\n'}) |
296 | - |
297 | - This will start mencoder to rip a video from DVD. This will also display |
298 | - progress ticks every 5 seconds as it runs. For example:: |
299 | - |
300 | - from pexpect import * #@UnusedWildImport |
301 | - def print_ticks(d): |
302 | - print d['event_count'], |
303 | - run ("mencoder dvd://1 -o video.avi -oac copy -ovc copy", events={TIMEOUT:print_ticks}, timeout=5) |
304 | - |
305 | - The 'events' argument should be a dictionary of patterns and responses. |
306 | - Whenever one of the patterns is seen in the command out run() will send the |
307 | - associated response string. Note that you should put newlines in your |
308 | - string if Enter is necessary. The responses may also contain callback |
309 | - functions. Any callback is function that takes a dictionary as an argument. |
310 | - The dictionary contains all the locals from the run() function, so you can |
311 | - access the child spawn object or any other variable defined in run() |
312 | - (event_count, child, and extra_args are the most useful). A callback may |
313 | - return True to stop the current run process otherwise run() continues until |
314 | - the next event. A callback may also return a string which will be sent to |
315 | - the child. 'extra_args' is not used by directly run(). It provides a way to |
316 | - pass data to a callback function through run() through the locals |
317 | - dictionary passed to a callback. """ |
318 | - |
319 | - if timeout == -1: |
320 | - child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env) |
321 | - else: |
322 | - child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile, cwd=cwd, env=env) |
323 | - if events is not None: |
324 | - patterns = events.keys() |
325 | - responses = events.values() |
326 | - else: |
327 | - patterns=None # We assume that EOF or TIMEOUT will save us. |
328 | - responses=None |
329 | - child_result_list = [] |
330 | - event_count = 0 |
331 | - while 1: |
332 | - try: |
333 | - index = child.expect (patterns) |
334 | - if type(child.after) in types.StringTypes: |
335 | - child_result_list.append(child.before + child.after) |
336 | - else: # child.after may have been a TIMEOUT or EOF, so don't cat those. |
337 | - child_result_list.append(child.before) |
338 | - if type(responses[index]) in types.StringTypes: |
339 | - child.send(responses[index]) |
340 | - elif type(responses[index]) is types.FunctionType: |
341 | - callback_result = responses[index](locals()) |
342 | - sys.stdout.flush() |
343 | - if type(callback_result) in types.StringTypes: |
344 | - child.send(callback_result) |
345 | - elif callback_result: |
346 | - break |
347 | - else: |
348 | - raise TypeError ('The callback must be a string or function type.') |
349 | - event_count = event_count + 1 |
350 | - except TIMEOUT, e: |
351 | - child_result_list.append(child.before) |
352 | - break |
353 | - except EOF, e: |
354 | - child_result_list.append(child.before) |
355 | - break |
356 | - child_result = ''.join(child_result_list) |
357 | - if withexitstatus: |
358 | - child.close() |
359 | - return (child_result, child.exitstatus) |
360 | - else: |
361 | - return child_result |
362 | - |
363 | -class spawn (object): |
364 | - |
365 | - """This is the main class interface for Pexpect. Use this class to start |
366 | - and control child applications. """ |
367 | - |
368 | - def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None): |
369 | - |
370 | - """This is the constructor. The command parameter may be a string that |
371 | - includes a command and any arguments to the command. For example:: |
372 | - |
373 | - child = pexpect.spawn ('/usr/bin/ftp') |
374 | - child = pexpect.spawn ('/usr/bin/ssh user@example.com') |
375 | - child = pexpect.spawn ('ls -latr /tmp') |
376 | - |
377 | - You may also construct it with a list of arguments like so:: |
378 | - |
379 | - child = pexpect.spawn ('/usr/bin/ftp', []) |
380 | - child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com']) |
381 | - child = pexpect.spawn ('ls', ['-latr', '/tmp']) |
382 | - |
383 | - After this the child application will be created and will be ready to |
384 | - talk to. For normal use, see expect() and send() and sendline(). |
385 | - |
386 | - Remember that Pexpect does NOT interpret shell meta characters such as |
387 | - redirect, pipe, or wild cards (>, |, or *). This is a common mistake. |
388 | - If you want to run a command and pipe it through another command then |
389 | - you must also start a shell. For example:: |
390 | - |
391 | - child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > log_list.txt"') |
392 | - child.expect(pexpect.EOF) |
393 | - |
394 | - The second form of spawn (where you pass a list of arguments) is useful |
395 | - in situations where you wish to spawn a command and pass it its own |
396 | - argument list. This can make syntax more clear. For example, the |
397 | - following is equivalent to the previous example:: |
398 | - |
399 | - shell_cmd = 'ls -l | grep LOG > log_list.txt' |
400 | - child = pexpect.spawn('/bin/bash', ['-c', shell_cmd]) |
401 | - child.expect(pexpect.EOF) |
402 | - |
403 | - The maxread attribute sets the read buffer size. This is maximum number |
404 | - of bytes that Pexpect will try to read from a TTY at one time. Setting |
405 | - the maxread size to 1 will turn off buffering. Setting the maxread |
406 | - value higher may help performance in cases where large amounts of |
407 | - output are read back from the child. This feature is useful in |
408 | - conjunction with searchwindowsize. |
409 | - |
410 | - The searchwindowsize attribute sets the how far back in the incomming |
411 | - seach buffer Pexpect will search for pattern matches. Every time |
412 | - Pexpect reads some data from the child it will append the data to the |
413 | - incomming buffer. The default is to search from the beginning of the |
414 | - imcomming buffer each time new data is read from the child. But this is |
415 | - very inefficient if you are running a command that generates a large |
416 | - amount of data where you want to match The searchwindowsize does not |
417 | - effect the size of the incomming data buffer. You will still have |
418 | - access to the full buffer after expect() returns. |
419 | - |
420 | - The logfile member turns on or off logging. All input and output will |
421 | - be copied to the given file object. Set logfile to None to stop |
422 | - logging. This is the default. Set logfile to sys.stdout to echo |
423 | - everything to standard output. The logfile is flushed after each write. |
424 | - |
425 | - Example log input and output to a file:: |
426 | - |
427 | - child = pexpect.spawn('some_command') |
428 | - fout = file('mylog.txt','w') |
429 | - child.logfile = fout |
430 | - |
431 | - Example log to stdout:: |
432 | - |
433 | - child = pexpect.spawn('some_command') |
434 | - child.logfile = sys.stdout |
435 | - |
436 | - The logfile_read and logfile_send members can be used to separately log |
437 | - the input from the child and output sent to the child. Sometimes you |
438 | - don't want to see everything you write to the child. You only want to |
439 | - log what the child sends back. For example:: |
440 | - |
441 | - child = pexpect.spawn('some_command') |
442 | - child.logfile_read = sys.stdout |
443 | - |
444 | - To separately log output sent to the child use logfile_send:: |
445 | - |
446 | - self.logfile_send = fout |
447 | - |
448 | - The delaybeforesend helps overcome a weird behavior that many users |
449 | - were experiencing. The typical problem was that a user would expect() a |
450 | - "Password:" prompt and then immediately call sendline() to send the |
451 | - password. The user would then see that their password was echoed back |
452 | - to them. Passwords don't normally echo. The problem is caused by the |
453 | - fact that most applications print out the "Password" prompt and then |
454 | - turn off stdin echo, but if you send your password before the |
455 | - application turned off echo, then you get your password echoed. |
456 | - Normally this wouldn't be a problem when interacting with a human at a |
457 | - real keyboard. If you introduce a slight delay just before writing then |
458 | - this seems to clear up the problem. This was such a common problem for |
459 | - many users that I decided that the default pexpect behavior should be |
460 | - to sleep just before writing to the child application. 1/20th of a |
461 | - second (50 ms) seems to be enough to clear up the problem. You can set |
462 | - delaybeforesend to 0 to return to the old behavior. Most Linux machines |
463 | - don't like this to be below 0.03. I don't know why. |
464 | - |
465 | - Note that spawn is clever about finding commands on your path. |
466 | - It uses the same logic that "which" uses to find executables. |
467 | - |
468 | - If you wish to get the exit status of the child you must call the |
469 | - close() method. The exit or signal status of the child will be stored |
470 | - in self.exitstatus or self.signalstatus. If the child exited normally |
471 | - then exitstatus will store the exit return code and signalstatus will |
472 | - be None. If the child was terminated abnormally with a signal then |
473 | - signalstatus will store the signal value and exitstatus will be None. |
474 | - If you need more detail you can also read the self.status member which |
475 | - stores the status returned by os.waitpid. You can interpret this using |
476 | - os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG. """ |
477 | - |
478 | - self.STDIN_FILENO = pty.STDIN_FILENO |
479 | - self.STDOUT_FILENO = pty.STDOUT_FILENO |
480 | - self.STDERR_FILENO = pty.STDERR_FILENO |
481 | - self.stdin = sys.stdin |
482 | - self.stdout = sys.stdout |
483 | - self.stderr = sys.stderr |
484 | - |
485 | - self.searcher = None |
486 | - self.ignorecase = False |
487 | - self.before = None |
488 | - self.after = None |
489 | - self.match = None |
490 | - self.match_index = None |
491 | - self.terminated = True |
492 | - self.exitstatus = None |
493 | - self.signalstatus = None |
494 | - self.status = None # status returned by os.waitpid |
495 | - self.flag_eof = False |
496 | - self.pid = None |
497 | - self.child_fd = -1 # initially closed |
498 | - self.timeout = timeout |
499 | - self.delimiter = EOF |
500 | - self.logfile = logfile |
501 | - self.logfile_read = None # input from child (read_nonblocking) |
502 | - self.logfile_send = None # output to send (send, sendline) |
503 | - self.maxread = maxread # max bytes to read at one time into buffer |
504 | - self.buffer = '' # This is the read buffer. See maxread. |
505 | - self.searchwindowsize = searchwindowsize # Anything before searchwindowsize point is preserved, but not searched. |
506 | - # Most Linux machines don't like delaybeforesend to be below 0.03 (30 ms). |
507 | - self.delaybeforesend = 0.05 # Sets sleep time used just before sending data to child. Time in seconds. |
508 | - self.delayafterclose = 0.1 # Sets delay in close() method to allow kernel time to update process status. Time in seconds. |
509 | - self.delayafterterminate = 0.1 # Sets delay in terminate() method to allow kernel time to update process status. Time in seconds. |
510 | - self.softspace = False # File-like object. |
511 | - self.name = '<' + repr(self) + '>' # File-like object. |
512 | - self.encoding = None # File-like object. |
513 | - self.closed = True # File-like object. |
514 | - self.cwd = cwd |
515 | - self.env = env |
516 | - self.__irix_hack = (sys.platform.lower().find('irix')>=0) # This flags if we are running on irix |
517 | - # Solaris uses internal __fork_pty(). All others use pty.fork(). |
518 | - if (sys.platform.lower().find('solaris')>=0) or (sys.platform.lower().find('sunos5')>=0): |
519 | - self.use_native_pty_fork = False |
520 | - else: |
521 | - self.use_native_pty_fork = True |
522 | - |
523 | - |
524 | - # allow dummy instances for subclasses that may not use command or args. |
525 | - if command is None: |
526 | - self.command = None |
527 | - self.args = None |
528 | - self.name = '<pexpect factory incomplete>' |
529 | - else: |
530 | - self._spawn (command, args) |
531 | - |
532 | - def __del__(self): |
533 | - |
534 | - """This makes sure that no system resources are left open. Python only |
535 | - garbage collects Python objects. OS file descriptors are not Python |
536 | - objects, so they must be handled explicitly. If the child file |
537 | - descriptor was opened outside of this class (passed to the constructor) |
538 | - then this does not close it. """ |
539 | - |
540 | - if not self.closed: |
541 | - # It is possible for __del__ methods to execute during the |
542 | - # teardown of the Python VM itself. Thus self.close() may |
543 | - # trigger an exception because os.close may be None. |
544 | - # -- Fernando Perez |
545 | - try: |
546 | - self.close() |
547 | - except AttributeError: |
548 | - pass |
549 | - |
550 | - def __str__(self): |
551 | - |
552 | - """This returns a human-readable string that represents the state of |
553 | - the object. """ |
554 | - |
555 | - s = [] |
556 | - s.append(repr(self)) |
557 | - s.append('version: ' + __version__ + ' (' + __revision__ + ')') |
558 | - s.append('command: ' + str(self.command)) |
559 | - s.append('args: ' + str(self.args)) |
560 | - s.append('searcher: ' + str(self.searcher)) |
561 | - s.append('buffer (last 100 chars): ' + str(self.buffer)[-100:]) |
562 | - s.append('before (last 100 chars): ' + str(self.before)[-100:]) |
563 | - s.append('after: ' + str(self.after)) |
564 | - s.append('match: ' + str(self.match)) |
565 | - s.append('match_index: ' + str(self.match_index)) |
566 | - s.append('exitstatus: ' + str(self.exitstatus)) |
567 | - s.append('flag_eof: ' + str(self.flag_eof)) |
568 | - s.append('pid: ' + str(self.pid)) |
569 | - s.append('child_fd: ' + str(self.child_fd)) |
570 | - s.append('closed: ' + str(self.closed)) |
571 | - s.append('timeout: ' + str(self.timeout)) |
572 | - s.append('delimiter: ' + str(self.delimiter)) |
573 | - s.append('logfile: ' + str(self.logfile)) |
574 | - s.append('logfile_read: ' + str(self.logfile_read)) |
575 | - s.append('logfile_send: ' + str(self.logfile_send)) |
576 | - s.append('maxread: ' + str(self.maxread)) |
577 | - s.append('ignorecase: ' + str(self.ignorecase)) |
578 | - s.append('searchwindowsize: ' + str(self.searchwindowsize)) |
579 | - s.append('delaybeforesend: ' + str(self.delaybeforesend)) |
580 | - s.append('delayafterclose: ' + str(self.delayafterclose)) |
581 | - s.append('delayafterterminate: ' + str(self.delayafterterminate)) |
582 | - return '\n'.join(s) |
583 | - |
584 | - def _spawn(self,command,args=[]): |
585 | - |
586 | - """This starts the given command in a child process. This does all the |
587 | - fork/exec type of stuff for a pty. This is called by __init__. If args |
588 | - is empty then command will be parsed (split on spaces) and args will be |
589 | - set to parsed arguments. """ |
590 | - |
591 | - # The pid and child_fd of this object get set by this method. |
592 | - # Note that it is difficult for this method to fail. |
593 | - # You cannot detect if the child process cannot start. |
594 | - # So the only way you can tell if the child process started |
595 | - # or not is to try to read from the file descriptor. If you get |
596 | - # EOF immediately then it means that the child is already dead. |
597 | - # That may not necessarily be bad because you may haved spawned a child |
598 | - # that performs some task; creates no stdout output; and then dies. |
599 | - |
600 | - # If command is an int type then it may represent a file descriptor. |
601 | - if type(command) == type(0): |
602 | - raise ExceptionPexpect ('Command is an int type. If this is a file descriptor then maybe you want to use fdpexpect.fdspawn which takes an existing file descriptor instead of a command string.') |
603 | - |
604 | - if type (args) != type([]): |
605 | - raise TypeError ('The argument, args, must be a list.') |
606 | - |
607 | - if args == []: |
608 | - self.args = split_command_line(command) |
609 | - self.command = self.args[0] |
610 | - else: |
611 | - self.args = args[:] # work with a copy |
612 | - self.args.insert (0, command) |
613 | - self.command = command |
614 | - |
615 | - command_with_path = which(self.command) |
616 | - if command_with_path is None: |
617 | - raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command) |
618 | - self.command = command_with_path |
619 | - self.args[0] = self.command |
620 | - |
621 | - self.name = '<' + ' '.join (self.args) + '>' |
622 | - |
623 | - assert self.pid is None, 'The pid member should be None.' |
624 | - assert self.command is not None, 'The command member should not be None.' |
625 | - |
626 | - if self.use_native_pty_fork: |
627 | - try: |
628 | - self.pid, self.child_fd = pty.fork() |
629 | - except OSError, e: |
630 | - raise ExceptionPexpect('Error! pty.fork() failed: ' + str(e)) |
631 | - else: # Use internal __fork_pty |
632 | - self.pid, self.child_fd = self.__fork_pty() |
633 | - |
634 | - if self.pid == 0: # Child |
635 | - try: |
636 | - self.child_fd = sys.stdout.fileno() # used by setwinsize() |
637 | - self.setwinsize(24, 80) |
638 | - except Exception: |
639 | - # Some platforms do not like setwinsize (Cygwin). |
640 | - # This will cause problem when running applications that |
641 | - # are very picky about window size. |
642 | - # This is a serious limitation, but not a show stopper. |
643 | - pass |
644 | - # Do not allow child to inherit open file descriptors from parent. |
645 | - max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0] |
646 | - for i in range (3, max_fd): |
647 | - try: |
648 | - os.close (i) |
649 | - except OSError: |
650 | - pass |
651 | - |
652 | - # I don't know why this works, but ignoring SIGHUP fixes a |
653 | - # problem when trying to start a Java daemon with sudo |
654 | - # (specifically, Tomcat). |
655 | - signal.signal(signal.SIGHUP, signal.SIG_IGN) |
656 | - |
657 | - if self.cwd is not None: |
658 | - os.chdir(self.cwd) |
659 | - if self.env is None: |
660 | - os.execv(self.command, self.args) |
661 | - else: |
662 | - os.execvpe(self.command, self.args, self.env) |
663 | - |
664 | - # Parent |
665 | - self.terminated = False |
666 | - self.closed = False |
667 | - |
668 | - def __fork_pty(self): |
669 | - |
670 | - """This implements a substitute for the forkpty system call. This |
671 | - should be more portable than the pty.fork() function. Specifically, |
672 | - this should work on Solaris. |
673 | - |
674 | - Modified 10.06.05 by Geoff Marshall: Implemented __fork_pty() method to |
675 | - resolve the issue with Python's pty.fork() not supporting Solaris, |
676 | - particularly ssh. Based on patch to posixmodule.c authored by Noah |
677 | - Spurrier:: |
678 | - |
679 | - http://mail.python.org/pipermail/python-dev/2003-May/035281.html |
680 | - |
681 | - """ |
682 | - |
683 | - parent_fd, child_fd = os.openpty() |
684 | - if parent_fd < 0 or child_fd < 0: |
685 | - raise ExceptionPexpect, "Error! Could not open pty with os.openpty()." |
686 | - |
687 | - pid = os.fork() |
688 | - if pid < 0: |
689 | - raise ExceptionPexpect, "Error! Failed os.fork()." |
690 | - elif pid == 0: |
691 | - # Child. |
692 | - os.close(parent_fd) |
693 | - self.__pty_make_controlling_tty(child_fd) |
694 | - |
695 | - os.dup2(child_fd, 0) |
696 | - os.dup2(child_fd, 1) |
697 | - os.dup2(child_fd, 2) |
698 | - |
699 | - if child_fd > 2: |
700 | - os.close(child_fd) |
701 | - else: |
702 | - # Parent. |
703 | - os.close(child_fd) |
704 | - |
705 | - return pid, parent_fd |
706 | - |
707 | - def __pty_make_controlling_tty(self, tty_fd): |
708 | - |
709 | - """This makes the pseudo-terminal the controlling tty. This should be |
710 | - more portable than the pty.fork() function. Specifically, this should |
711 | - work on Solaris. """ |
712 | - |
713 | - child_name = os.ttyname(tty_fd) |
714 | - |
715 | - # Disconnect from controlling tty if still connected. |
716 | - fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY); |
717 | - if fd >= 0: |
718 | - os.close(fd) |
719 | - |
720 | - os.setsid() |
721 | - |
722 | - # Verify we are disconnected from controlling tty |
723 | - try: |
724 | - fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY); |
725 | - if fd >= 0: |
726 | - os.close(fd) |
727 | - raise ExceptionPexpect, "Error! We are not disconnected from a controlling tty." |
728 | - except Exception: |
729 | - # Good! We are disconnected from a controlling tty. |
730 | - pass |
731 | - |
732 | - # Verify we can open child pty. |
733 | - fd = os.open(child_name, os.O_RDWR); |
734 | - if fd < 0: |
735 | - raise ExceptionPexpect, "Error! Could not open child pty, " + child_name |
736 | - else: |
737 | - os.close(fd) |
738 | - |
739 | - # Verify we now have a controlling tty. |
740 | - fd = os.open("/dev/tty", os.O_WRONLY) |
741 | - if fd < 0: |
742 | - raise ExceptionPexpect, "Error! Could not open controlling tty, /dev/tty" |
743 | - else: |
744 | - os.close(fd) |
745 | - |
746 | - def fileno (self): # File-like object. |
747 | - |
748 | - """This returns the file descriptor of the pty for the child. |
749 | - """ |
750 | - |
751 | - return self.child_fd |
752 | - |
753 | - def close (self, force=True): # File-like object. |
754 | - |
755 | - """This closes the connection with the child application. Note that |
756 | - calling close() more than once is valid. This emulates standard Python |
757 | - behavior with files. Set force to True if you want to make sure that |
758 | - the child is terminated (SIGKILL is sent if the child ignores SIGHUP |
759 | - and SIGINT). """ |
760 | - |
761 | - if not self.closed: |
762 | - self.flush() |
763 | - os.close (self.child_fd) |
764 | - time.sleep(self.delayafterclose) # Give kernel time to update process status. |
765 | - if self.isalive(): |
766 | - if not self.terminate(force): |
767 | - raise ExceptionPexpect ('close() could not terminate the child using terminate()') |
768 | - self.child_fd = -1 |
769 | - self.closed = True |
770 | - #self.pid = None |
771 | - |
772 | - def flush (self): # File-like object. |
773 | - |
774 | - """This does nothing. It is here to support the interface for a |
775 | - File-like object. """ |
776 | - |
777 | - pass |
778 | - |
779 | - def isatty (self): # File-like object. |
780 | - |
781 | - """This returns True if the file descriptor is open and connected to a |
782 | - tty(-like) device, else False. """ |
783 | - |
784 | - return os.isatty(self.child_fd) |
785 | - |
786 | - def waitnoecho (self, timeout=-1): |
787 | - |
788 | - """This waits until the terminal ECHO flag is set False. This returns |
789 | - True if the echo mode is off. This returns False if the ECHO flag was |
790 | - not set False before the timeout. This can be used to detect when the |
791 | - child is waiting for a password. Usually a child application will turn |
792 | - off echo mode when it is waiting for the user to enter a password. For |
793 | - example, instead of expecting the "password:" prompt you can wait for |
794 | - the child to set ECHO off:: |
795 | - |
796 | - p = pexpect.spawn ('ssh user@example.com') |
797 | - p.waitnoecho() |
798 | - p.sendline(mypassword) |
799 | - |
800 | - If timeout is None then this method to block forever until ECHO flag is |
801 | - False. |
802 | - |
803 | - """ |
804 | - |
805 | - if timeout == -1: |
806 | - timeout = self.timeout |
807 | - if timeout is not None: |
808 | - end_time = time.time() + timeout |
809 | - while True: |
810 | - if not self.getecho(): |
811 | - return True |
812 | - if timeout < 0 and timeout is not None: |
813 | - return False |
814 | - if timeout is not None: |
815 | - timeout = end_time - time.time() |
816 | - time.sleep(0.1) |
817 | - |
818 | - def getecho (self): |
819 | - |
820 | - """This returns the terminal echo mode. This returns True if echo is |
821 | - on or False if echo is off. Child applications that are expecting you |
822 | - to enter a password often set ECHO False. See waitnoecho(). """ |
823 | - |
824 | - attr = termios.tcgetattr(self.child_fd) |
825 | - if attr[3] & termios.ECHO: |
826 | - return True |
827 | - return False |
828 | - |
829 | - def setecho (self, state): |
830 | - |
831 | - """This sets the terminal echo mode on or off. Note that anything the |
832 | - child sent before the echo will be lost, so you should be sure that |
833 | - your input buffer is empty before you call setecho(). For example, the |
834 | - following will work as expected:: |
835 | - |
836 | - p = pexpect.spawn('cat') |
837 | - p.sendline ('1234') # We will see this twice (once from tty echo and again from cat). |
838 | - p.expect (['1234']) |
839 | - p.expect (['1234']) |
840 | - p.setecho(False) # Turn off tty echo |
841 | - p.sendline ('abcd') # We will set this only once (echoed by cat). |
842 | - p.sendline ('wxyz') # We will set this only once (echoed by cat) |
843 | - p.expect (['abcd']) |
844 | - p.expect (['wxyz']) |
845 | - |
846 | - The following WILL NOT WORK because the lines sent before the setecho |
847 | - will be lost:: |
848 | - |
849 | - p = pexpect.spawn('cat') |
850 | - p.sendline ('1234') # We will see this twice (once from tty echo and again from cat). |
851 | - p.setecho(False) # Turn off tty echo |
852 | - p.sendline ('abcd') # We will set this only once (echoed by cat). |
853 | - p.sendline ('wxyz') # We will set this only once (echoed by cat) |
854 | - p.expect (['1234']) |
855 | - p.expect (['1234']) |
856 | - p.expect (['abcd']) |
857 | - p.expect (['wxyz']) |
858 | - """ |
859 | - |
860 | - self.child_fd |
861 | - attr = termios.tcgetattr(self.child_fd) |
862 | - if state: |
863 | - attr[3] = attr[3] | termios.ECHO |
864 | - else: |
865 | - attr[3] = attr[3] & ~termios.ECHO |
866 | - # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent |
867 | - # and blocked on some platforms. TCSADRAIN is probably ideal if it worked. |
868 | - termios.tcsetattr(self.child_fd, termios.TCSANOW, attr) |
869 | - |
870 | - def read_nonblocking (self, size = 1, timeout = -1): |
871 | - |
872 | - """This reads at most size characters from the child application. It |
873 | - includes a timeout. If the read does not complete within the timeout |
874 | - period then a TIMEOUT exception is raised. If the end of file is read |
875 | - then an EOF exception will be raised. If a log file was set using |
876 | - setlog() then all data will also be written to the log file. |
877 | - |
878 | - If timeout is None then the read may block indefinitely. If timeout is -1 |
879 | - then the self.timeout value is used. If timeout is 0 then the child is |
880 | - polled and if there was no data immediately ready then this will raise |
881 | - a TIMEOUT exception. |
882 | - |
883 | - The timeout refers only to the amount of time to read at least one |
884 | - character. This is not effected by the 'size' parameter, so if you call |
885 | - read_nonblocking(size=100, timeout=30) and only one character is |
886 | - available right away then one character will be returned immediately. |
887 | - It will not wait for 30 seconds for another 99 characters to come in. |
888 | - |
889 | - This is a wrapper around os.read(). It uses select.select() to |
890 | - implement the timeout. """ |
891 | - |
892 | - if self.closed: |
893 | - raise ValueError ('I/O operation on closed file in read_nonblocking().') |
894 | - |
895 | - if timeout == -1: |
896 | - timeout = self.timeout |
897 | - |
898 | - # Note that some systems such as Solaris do not give an EOF when |
899 | - # the child dies. In fact, you can still try to read |
900 | - # from the child_fd -- it will block forever or until TIMEOUT. |
901 | - # For this case, I test isalive() before doing any reading. |
902 | - # If isalive() is false, then I pretend that this is the same as EOF. |
903 | - if not self.isalive(): |
904 | - r,w,e = self.__select([self.child_fd], [], [], 0) # timeout of 0 means "poll" @UnusedVariable |
905 | - if not r: |
906 | - self.flag_eof = True |
907 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Braindead platform.') |
908 | - elif self.__irix_hack: |
909 | - # This is a hack for Irix. It seems that Irix requires a long delay before checking isalive. |
910 | - # This adds a 2 second delay, but only when the child is terminated. |
911 | - r, w, e = self.__select([self.child_fd], [], [], 2) #@UnusedVariable |
912 | - if not r and not self.isalive(): |
913 | - self.flag_eof = True |
914 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Pokey platform.') |
915 | - |
916 | - r,w,e = self.__select([self.child_fd], [], [], timeout) #@UnusedVariable |
917 | - |
918 | - if not r: |
919 | - if not self.isalive(): |
920 | - # Some platforms, such as Irix, will claim that their processes are alive; |
921 | - # then timeout on the select; and then finally admit that they are not alive. |
922 | - self.flag_eof = True |
923 | - raise EOF ('End of File (EOF) in read_nonblocking(). Very pokey platform.') |
924 | - else: |
925 | - raise TIMEOUT ('Timeout exceeded in read_nonblocking().') |
926 | - |
927 | - if self.child_fd in r: |
928 | - try: |
929 | - s = os.read(self.child_fd, size) |
930 | - except OSError, e: # Linux does this |
931 | - self.flag_eof = True |
932 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Exception style platform.') |
933 | - if s == '': # BSD style |
934 | - self.flag_eof = True |
935 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Empty string style platform.') |
936 | - |
937 | - if self.logfile is not None: |
938 | - self.logfile.write (s) |
939 | - self.logfile.flush() |
940 | - if self.logfile_read is not None: |
941 | - self.logfile_read.write (s) |
942 | - self.logfile_read.flush() |
943 | - |
944 | - return s |
945 | - |
946 | - raise ExceptionPexpect ('Reached an unexpected state in read_nonblocking().') |
947 | - |
948 | - def read (self, size = -1): # File-like object. |
949 | - |
950 | - """This reads at most "size" bytes from the file (less if the read hits |
951 | - EOF before obtaining size bytes). If the size argument is negative or |
952 | - omitted, read all data until EOF is reached. The bytes are returned as |
953 | - a string object. An empty string is returned when EOF is encountered |
954 | - immediately. """ |
955 | - |
956 | - if size == 0: |
957 | - return '' |
958 | - if size < 0: |
959 | - self.expect (self.delimiter) # delimiter default is EOF |
960 | - return self.before |
961 | - |
962 | - # I could have done this more directly by not using expect(), but |
963 | - # I deliberately decided to couple read() to expect() so that |
964 | - # I would catch any bugs early and ensure consistant behavior. |
965 | - # It's a little less efficient, but there is less for me to |
966 | - # worry about if I have to later modify read() or expect(). |
967 | - # Note, it's OK if size==-1 in the regex. That just means it |
968 | - # will never match anything in which case we stop only on EOF. |
969 | - cre = re.compile('.{%d}' % size, re.DOTALL) |
970 | - index = self.expect ([cre, self.delimiter]) # delimiter default is EOF |
971 | - if index == 0: |
972 | - return self.after ### self.before should be ''. Should I assert this? |
973 | - return self.before |
974 | - |
975 | - def readline (self, size = -1): # File-like object. |
976 | - |
977 | - """This reads and returns one entire line. A trailing newline is kept |
978 | - in the string, but may be absent when a file ends with an incomplete |
979 | - line. Note: This readline() looks for a \\r\\n pair even on UNIX |
980 | - because this is what the pseudo tty device returns. So contrary to what |
981 | - you may expect you will receive the newline as \\r\\n. An empty string |
982 | - is returned when EOF is hit immediately. Currently, the size argument is |
983 | - mostly ignored, so this behavior is not standard for a file-like |
984 | - object. If size is 0 then an empty string is returned. """ |
985 | - |
986 | - if size == 0: |
987 | - return '' |
988 | - index = self.expect (['\r\n', self.delimiter]) # delimiter default is EOF |
989 | - if index == 0: |
990 | - return self.before + '\r\n' |
991 | - else: |
992 | - return self.before |
993 | - |
994 | - def __iter__ (self): # File-like object. |
995 | - |
996 | - """This is to support iterators over a file-like object. |
997 | - """ |
998 | - |
999 | - return self |
1000 | - |
1001 | - def next (self): # File-like object. |
1002 | - |
1003 | - """This is to support iterators over a file-like object. |
1004 | - """ |
1005 | - |
1006 | - result = self.readline() |
1007 | - if result == "": |
1008 | - raise StopIteration |
1009 | - return result |
1010 | - |
1011 | - def readlines (self, sizehint = -1): # File-like object. |
1012 | - |
1013 | - """This reads until EOF using readline() and returns a list containing |
1014 | - the lines thus read. The optional "sizehint" argument is ignored. """ |
1015 | - |
1016 | - lines = [] |
1017 | - while True: |
1018 | - line = self.readline() |
1019 | - if not line: |
1020 | - break |
1021 | - lines.append(line) |
1022 | - return lines |
1023 | - |
1024 | - def write(self, s): # File-like object. |
1025 | - |
1026 | - """This is similar to send() except that there is no return value. |
1027 | - """ |
1028 | - |
1029 | - self.send (s) |
1030 | - |
1031 | - def writelines (self, sequence): # File-like object. |
1032 | - |
1033 | - """This calls write() for each element in the sequence. The sequence |
1034 | - can be any iterable object producing strings, typically a list of |
1035 | - strings. This does not add line separators There is no return value. |
1036 | - """ |
1037 | - |
1038 | - for s in sequence: |
1039 | - self.write (s) |
1040 | - |
1041 | - def send(self, s): |
1042 | - |
1043 | - """This sends a string to the child process. This returns the number of |
1044 | - bytes written. If a log file was set then the data is also written to |
1045 | - the log. """ |
1046 | - |
1047 | - time.sleep(self.delaybeforesend) |
1048 | - if self.logfile is not None: |
1049 | - self.logfile.write (s) |
1050 | - self.logfile.flush() |
1051 | - if self.logfile_send is not None: |
1052 | - self.logfile_send.write (s) |
1053 | - self.logfile_send.flush() |
1054 | - c = os.write(self.child_fd, s) |
1055 | - return c |
1056 | - |
1057 | - def sendline(self, s=''): |
1058 | - |
1059 | - """This is like send(), but it adds a line feed (os.linesep). This |
1060 | - returns the number of bytes written. """ |
1061 | - |
1062 | - n = self.send(s) |
1063 | - n = n + self.send (os.linesep) |
1064 | - return n |
1065 | - |
1066 | - def sendcontrol(self, char): |
1067 | - |
1068 | - """This sends a control character to the child such as Ctrl-C or |
1069 | - Ctrl-D. For example, to send a Ctrl-G (ASCII 7):: |
1070 | - |
1071 | - child.sendcontrol('g') |
1072 | - |
1073 | - See also, sendintr() and sendeof(). |
1074 | - """ |
1075 | - |
1076 | - char = char.lower() |
1077 | - a = ord(char) |
1078 | - if a>=97 and a<=122: |
1079 | - a = a - ord('a') + 1 |
1080 | - return self.send (chr(a)) |
1081 | - d = {'@':0, '`':0, |
1082 | - '[':27, '{':27, |
1083 | - '\\':28, '|':28, |
1084 | - ']':29, '}': 29, |
1085 | - '^':30, '~':30, |
1086 | - '_':31, |
1087 | - '?':127} |
1088 | - if char not in d: |
1089 | - return 0 |
1090 | - return self.send (chr(d[char])) |
1091 | - |
1092 | - def sendeof(self): |
1093 | - |
1094 | - """This sends an EOF to the child. This sends a character which causes |
1095 | - the pending parent output buffer to be sent to the waiting child |
1096 | - program without waiting for end-of-line. If it is the first character |
1097 | - of the line, the read() in the user program returns 0, which signifies |
1098 | - end-of-file. This means to work as expected a sendeof() has to be |
1099 | - called at the beginning of a line. This method does not send a newline. |
1100 | - It is the responsibility of the caller to ensure the eof is sent at the |
1101 | - beginning of a line. """ |
1102 | - |
1103 | - ### Hmmm... how do I send an EOF? |
1104 | - ###C if ((m = write(pty, *buf, p - *buf)) < 0) |
1105 | - ###C return (errno == EWOULDBLOCK) ? n : -1; |
1106 | - #fd = sys.stdin.fileno() |
1107 | - #old = termios.tcgetattr(fd) # remember current state |
1108 | - #attr = termios.tcgetattr(fd) |
1109 | - #attr[3] = attr[3] | termios.ICANON # ICANON must be set to recognize EOF |
1110 | - #try: # use try/finally to ensure state gets restored |
1111 | - # termios.tcsetattr(fd, termios.TCSADRAIN, attr) |
1112 | - # if hasattr(termios, 'CEOF'): |
1113 | - # os.write (self.child_fd, '%c' % termios.CEOF) |
1114 | - # else: |
1115 | - # # Silly platform does not define CEOF so assume CTRL-D |
1116 | - # os.write (self.child_fd, '%c' % 4) |
1117 | - #finally: # restore state |
1118 | - # termios.tcsetattr(fd, termios.TCSADRAIN, old) |
1119 | - if hasattr(termios, 'VEOF'): |
1120 | - char = termios.tcgetattr(self.child_fd)[6][termios.VEOF] |
1121 | - else: |
1122 | - # platform does not define VEOF so assume CTRL-D |
1123 | - char = chr(4) |
1124 | - self.send(char) |
1125 | - |
1126 | - def sendintr(self): |
1127 | - |
1128 | - """This sends a SIGINT to the child. It does not require |
1129 | - the SIGINT to be the first character on a line. """ |
1130 | - |
1131 | - if hasattr(termios, 'VINTR'): |
1132 | - char = termios.tcgetattr(self.child_fd)[6][termios.VINTR] |
1133 | - else: |
1134 | - # platform does not define VINTR so assume CTRL-C |
1135 | - char = chr(3) |
1136 | - self.send (char) |
1137 | - |
1138 | - def eof (self): |
1139 | - |
1140 | - """This returns True if the EOF exception was ever raised. |
1141 | - """ |
1142 | - |
1143 | - return self.flag_eof |
1144 | - |
1145 | - def terminate(self, force=False): |
1146 | - |
1147 | - """This forces a child process to terminate. It starts nicely with |
1148 | - SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This |
1149 | - returns True if the child was terminated. This returns False if the |
1150 | - child could not be terminated. """ |
1151 | - |
1152 | - if not self.isalive(): |
1153 | - return True |
1154 | - try: |
1155 | - self.kill(signal.SIGHUP) |
1156 | - time.sleep(self.delayafterterminate) |
1157 | - if not self.isalive(): |
1158 | - return True |
1159 | - self.kill(signal.SIGCONT) |
1160 | - time.sleep(self.delayafterterminate) |
1161 | - if not self.isalive(): |
1162 | - return True |
1163 | - self.kill(signal.SIGINT) |
1164 | - time.sleep(self.delayafterterminate) |
1165 | - if not self.isalive(): |
1166 | - return True |
1167 | - if force: |
1168 | - self.kill(signal.SIGKILL) |
1169 | - time.sleep(self.delayafterterminate) |
1170 | - if not self.isalive(): |
1171 | - return True |
1172 | - else: |
1173 | - return False |
1174 | - return False |
1175 | - except OSError, e: |
1176 | - # I think there are kernel timing issues that sometimes cause |
1177 | - # this to happen. I think isalive() reports True, but the |
1178 | - # process is dead to the kernel. |
1179 | - # Make one last attempt to see if the kernel is up to date. |
1180 | - time.sleep(self.delayafterterminate) |
1181 | - if not self.isalive(): |
1182 | - return True |
1183 | - else: |
1184 | - return False |
1185 | - |
1186 | - def wait(self): |
1187 | - |
1188 | - """This waits until the child exits. This is a blocking call. This will |
1189 | - not read any data from the child, so this will block forever if the |
1190 | - child has unread output and has terminated. In other words, the child |
1191 | - may have printed output then called exit(); but, technically, the child |
1192 | - is still alive until its output is read. """ |
1193 | - |
1194 | - if self.isalive(): |
1195 | - pid, status = os.waitpid(self.pid, 0) #@UnusedVariable |
1196 | - else: |
1197 | - raise ExceptionPexpect ('Cannot wait for dead child process.') |
1198 | - self.exitstatus = os.WEXITSTATUS(status) |
1199 | - if os.WIFEXITED (status): |
1200 | - self.status = status |
1201 | - self.exitstatus = os.WEXITSTATUS(status) |
1202 | - self.signalstatus = None |
1203 | - self.terminated = True |
1204 | - elif os.WIFSIGNALED (status): |
1205 | - self.status = status |
1206 | - self.exitstatus = None |
1207 | - self.signalstatus = os.WTERMSIG(status) |
1208 | - self.terminated = True |
1209 | - elif os.WIFSTOPPED (status): |
1210 | - raise ExceptionPexpect ('Wait was called for a child process that is stopped. This is not supported. Is some other process attempting job control with our child pid?') |
1211 | - return self.exitstatus |
1212 | - |
1213 | - def isalive(self): |
1214 | - |
1215 | - """This tests if the child process is running or not. This is |
1216 | - non-blocking. If the child was terminated then this will read the |
1217 | - exitstatus or signalstatus of the child. This returns True if the child |
1218 | - process appears to be running or False if not. It can take literally |
1219 | - SECONDS for Solaris to return the right status. """ |
1220 | - |
1221 | - if self.terminated: |
1222 | - return False |
1223 | - |
1224 | - if self.flag_eof: |
1225 | - # This is for Linux, which requires the blocking form of waitpid to get |
1226 | - # status of a defunct process. This is super-lame. The flag_eof would have |
1227 | - # been set in read_nonblocking(), so this should be safe. |
1228 | - waitpid_options = 0 |
1229 | - else: |
1230 | - waitpid_options = os.WNOHANG |
1231 | - |
1232 | - try: |
1233 | - pid, status = os.waitpid(self.pid, waitpid_options) |
1234 | - except OSError, e: # No child processes |
1235 | - if e[0] == errno.ECHILD: |
1236 | - raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?') |
1237 | - else: |
1238 | - raise e |
1239 | - |
1240 | - # I have to do this twice for Solaris. I can't even believe that I figured this out... |
1241 | - # If waitpid() returns 0 it means that no child process wishes to |
1242 | - # report, and the value of status is undefined. |
1243 | - if pid == 0: |
1244 | - try: |
1245 | - pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris! |
1246 | - except OSError, e: # This should never happen... |
1247 | - if e[0] == errno.ECHILD: |
1248 | - raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?') |
1249 | - else: |
1250 | - raise e |
1251 | - |
1252 | - # If pid is still 0 after two calls to waitpid() then |
1253 | - # the process really is alive. This seems to work on all platforms, except |
1254 | - # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking |
1255 | - # take care of this situation (unfortunately, this requires waiting through the timeout). |
1256 | - if pid == 0: |
1257 | - return True |
1258 | - |
1259 | - if pid == 0: |
1260 | - return True |
1261 | - |
1262 | - if os.WIFEXITED (status): |
1263 | - self.status = status |
1264 | - self.exitstatus = os.WEXITSTATUS(status) |
1265 | - self.signalstatus = None |
1266 | - self.terminated = True |
1267 | - elif os.WIFSIGNALED (status): |
1268 | - self.status = status |
1269 | - self.exitstatus = None |
1270 | - self.signalstatus = os.WTERMSIG(status) |
1271 | - self.terminated = True |
1272 | - elif os.WIFSTOPPED (status): |
1273 | - raise ExceptionPexpect ('isalive() encountered condition where child process is stopped. This is not supported. Is some other process attempting job control with our child pid?') |
1274 | - return False |
1275 | - |
1276 | - def kill(self, sig): |
1277 | - |
1278 | - """This sends the given signal to the child application. In keeping |
1279 | - with UNIX tradition it has a misleading name. It does not necessarily |
1280 | - kill the child unless you send the right signal. """ |
1281 | - |
1282 | - # Same as os.kill, but the pid is given for you. |
1283 | - if self.isalive(): |
1284 | - os.kill(self.pid, sig) |
1285 | - |
1286 | - def compile_pattern_list(self, patterns): |
1287 | - |
1288 | - """This compiles a pattern-string or a list of pattern-strings. |
1289 | - Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of |
1290 | - those. Patterns may also be None which results in an empty list (you |
1291 | - might do this if waiting for an EOF or TIMEOUT condition without |
1292 | - expecting any pattern). |
1293 | - |
1294 | - This is used by expect() when calling expect_list(). Thus expect() is |
1295 | - nothing more than:: |
1296 | - |
1297 | - cpl = self.compile_pattern_list(pl) |
1298 | - return self.expect_list(cpl, timeout) |
1299 | - |
1300 | - If you are using expect() within a loop it may be more |
1301 | - efficient to compile the patterns first and then call expect_list(). |
1302 | - This avoid calls in a loop to compile_pattern_list():: |
1303 | - |
1304 | - cpl = self.compile_pattern_list(my_pattern) |
1305 | - while some_condition: |
1306 | - ... |
1307 | - i = self.expect_list(clp, timeout) |
1308 | - ... |
1309 | - """ |
1310 | - |
1311 | - if patterns is None: |
1312 | - return [] |
1313 | - if type(patterns) is not types.ListType: |
1314 | - patterns = [patterns] |
1315 | - |
1316 | - compile_flags = re.DOTALL # Allow dot to match \n |
1317 | - if self.ignorecase: |
1318 | - compile_flags = compile_flags | re.IGNORECASE |
1319 | - compiled_pattern_list = [] |
1320 | - for p in patterns: |
1321 | - if type(p) in types.StringTypes: |
1322 | - compiled_pattern_list.append(re.compile(p, compile_flags)) |
1323 | - elif p is EOF: |
1324 | - compiled_pattern_list.append(EOF) |
1325 | - elif p is TIMEOUT: |
1326 | - compiled_pattern_list.append(TIMEOUT) |
1327 | - elif type(p) is type(re.compile('')): |
1328 | - compiled_pattern_list.append(p) |
1329 | - else: |
1330 | - raise TypeError ('Argument must be one of StringTypes, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p))) |
1331 | - |
1332 | - return compiled_pattern_list |
1333 | - |
1334 | - def expect(self, pattern, timeout = -1, searchwindowsize=None): |
1335 | - |
1336 | - """This seeks through the stream until a pattern is matched. The |
1337 | - pattern is overloaded and may take several types. The pattern can be a |
1338 | - StringType, EOF, a compiled re, or a list of any of those types. |
1339 | - Strings will be compiled to re types. This returns the index into the |
1340 | - pattern list. If the pattern was not a list this returns index 0 on a |
1341 | - successful match. This may raise exceptions for EOF or TIMEOUT. To |
1342 | - avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern |
1343 | - list. That will cause expect to match an EOF or TIMEOUT condition |
1344 | - instead of raising an exception. |
1345 | - |
1346 | - If you pass a list of patterns and more than one matches, the first match |
1347 | - in the stream is chosen. If more than one pattern matches at that point, |
1348 | - the leftmost in the pattern list is chosen. For example:: |
1349 | - |
1350 | - # the input is 'foobar' |
1351 | - index = p.expect (['bar', 'foo', 'foobar']) |
1352 | - # returns 1 ('foo') even though 'foobar' is a "better" match |
1353 | - |
1354 | - Please note, however, that buffering can affect this behavior, since |
1355 | - input arrives in unpredictable chunks. For example:: |
1356 | - |
1357 | - # the input is 'foobar' |
1358 | - index = p.expect (['foobar', 'foo']) |
1359 | - # returns 0 ('foobar') if all input is available at once, |
1360 | - # but returs 1 ('foo') if parts of the final 'bar' arrive late |
1361 | - |
1362 | - After a match is found the instance attributes 'before', 'after' and |
1363 | - 'match' will be set. You can see all the data read before the match in |
1364 | - 'before'. You can see the data that was matched in 'after'. The |
1365 | - re.MatchObject used in the re match will be in 'match'. If an error |
1366 | - occurred then 'before' will be set to all the data read so far and |
1367 | - 'after' and 'match' will be None. |
1368 | - |
1369 | - If timeout is -1 then timeout will be set to the self.timeout value. |
1370 | - |
1371 | - A list entry may be EOF or TIMEOUT instead of a string. This will |
1372 | - catch these exceptions and return the index of the list entry instead |
1373 | - of raising the exception. The attribute 'after' will be set to the |
1374 | - exception type. The attribute 'match' will be None. This allows you to |
1375 | - write code like this:: |
1376 | - |
1377 | - index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT]) |
1378 | - if index == 0: |
1379 | - do_something() |
1380 | - elif index == 1: |
1381 | - do_something_else() |
1382 | - elif index == 2: |
1383 | - do_some_other_thing() |
1384 | - elif index == 3: |
1385 | - do_something_completely_different() |
1386 | - |
1387 | - instead of code like this:: |
1388 | - |
1389 | - try: |
1390 | - index = p.expect (['good', 'bad']) |
1391 | - if index == 0: |
1392 | - do_something() |
1393 | - elif index == 1: |
1394 | - do_something_else() |
1395 | - except EOF: |
1396 | - do_some_other_thing() |
1397 | - except TIMEOUT: |
1398 | - do_something_completely_different() |
1399 | - |
1400 | - These two forms are equivalent. It all depends on what you want. You |
1401 | - can also just expect the EOF if you are waiting for all output of a |
1402 | - child to finish. For example:: |
1403 | - |
1404 | - p = pexpect.spawn('/bin/ls') |
1405 | - p.expect (pexpect.EOF) |
1406 | - print p.before |
1407 | - |
1408 | - If you are trying to optimize for speed then see expect_list(). |
1409 | - """ |
1410 | - |
1411 | - compiled_pattern_list = self.compile_pattern_list(pattern) |
1412 | - return self.expect_list(compiled_pattern_list, timeout, searchwindowsize) |
1413 | - |
1414 | - def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1): |
1415 | - |
1416 | - """This takes a list of compiled regular expressions and returns the |
1417 | - index into the pattern_list that matched the child output. The list may |
1418 | - also contain EOF or TIMEOUT (which are not compiled regular |
1419 | - expressions). This method is similar to the expect() method except that |
1420 | - expect_list() does not recompile the pattern list on every call. This |
1421 | - may help if you are trying to optimize for speed, otherwise just use |
1422 | - the expect() method. This is called by expect(). If timeout==-1 then |
1423 | - the self.timeout value is used. If searchwindowsize==-1 then the |
1424 | - self.searchwindowsize value is used. """ |
1425 | - |
1426 | - return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize) |
1427 | - |
1428 | - def expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1): |
1429 | - |
1430 | - """This is similar to expect(), but uses plain string matching instead |
1431 | - of compiled regular expressions in 'pattern_list'. The 'pattern_list' |
1432 | - may be a string; a list or other sequence of strings; or TIMEOUT and |
1433 | - EOF. |
1434 | - |
1435 | - This call might be faster than expect() for two reasons: string |
1436 | - searching is faster than RE matching and it is possible to limit the |
1437 | - search to just the end of the input buffer. |
1438 | - |
1439 | - This method is also useful when you don't want to have to worry about |
1440 | - escaping regular expression characters that you want to match.""" |
1441 | - |
1442 | - if type(pattern_list) in types.StringTypes or pattern_list in (TIMEOUT, EOF): |
1443 | - pattern_list = [pattern_list] |
1444 | - return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize) |
1445 | - |
1446 | - def expect_loop(self, searcher, timeout = -1, searchwindowsize = -1): |
1447 | - |
1448 | - """This is the common loop used inside expect. The 'searcher' should be |
1449 | - an instance of searcher_re or searcher_string, which describes how and what |
1450 | - to search for in the input. |
1451 | - |
1452 | - See expect() for other arguments, return value and exceptions. """ |
1453 | - |
1454 | - self.searcher = searcher |
1455 | - |
1456 | - if timeout == -1: |
1457 | - timeout = self.timeout |
1458 | - if timeout is not None: |
1459 | - end_time = time.time() + timeout |
1460 | - if searchwindowsize == -1: |
1461 | - searchwindowsize = self.searchwindowsize |
1462 | - |
1463 | - try: |
1464 | - incoming = self.buffer |
1465 | - freshlen = len(incoming) |
1466 | - while True: # Keep reading until exception or return. |
1467 | - index = searcher.search(incoming, freshlen, searchwindowsize) |
1468 | - if index >= 0: |
1469 | - self.buffer = incoming[searcher.end : ] |
1470 | - self.before = incoming[ : searcher.start] |
1471 | - self.after = incoming[searcher.start : searcher.end] |
1472 | - self.match = searcher.match |
1473 | - self.match_index = index |
1474 | - return self.match_index |
1475 | - # No match at this point |
1476 | - if timeout < 0 and timeout is not None: |
1477 | - raise TIMEOUT ('Timeout exceeded in expect_any().') |
1478 | - # Still have time left, so read more data |
1479 | - c = self.read_nonblocking (self.maxread, timeout) |
1480 | - freshlen = len(c) |
1481 | - time.sleep (0.0001) |
1482 | - incoming = incoming + c |
1483 | - if timeout is not None: |
1484 | - timeout = end_time - time.time() |
1485 | - except EOF, e: |
1486 | - self.buffer = '' |
1487 | - self.before = incoming |
1488 | - self.after = EOF |
1489 | - index = searcher.eof_index |
1490 | - if index >= 0: |
1491 | - self.match = EOF |
1492 | - self.match_index = index |
1493 | - return self.match_index |
1494 | - else: |
1495 | - self.match = None |
1496 | - self.match_index = None |
1497 | - raise EOF (str(e) + '\n' + str(self)) |
1498 | - except TIMEOUT, e: |
1499 | - self.buffer = incoming |
1500 | - self.before = incoming |
1501 | - self.after = TIMEOUT |
1502 | - index = searcher.timeout_index |
1503 | - if index >= 0: |
1504 | - self.match = TIMEOUT |
1505 | - self.match_index = index |
1506 | - return self.match_index |
1507 | - else: |
1508 | - self.match = None |
1509 | - self.match_index = None |
1510 | - raise TIMEOUT (str(e) + '\n' + str(self)) |
1511 | - except Exception: |
1512 | - self.before = incoming |
1513 | - self.after = None |
1514 | - self.match = None |
1515 | - self.match_index = None |
1516 | - raise |
1517 | - |
1518 | - def getwinsize(self): |
1519 | - |
1520 | - """This returns the terminal window size of the child tty. The return |
1521 | - value is a tuple of (rows, cols). """ |
1522 | - |
1523 | - TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L) |
1524 | - s = struct.pack('HHHH', 0, 0, 0, 0) |
1525 | - x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s) |
1526 | - return struct.unpack('HHHH', x)[0:2] |
1527 | - |
1528 | - def setwinsize(self, r, c): |
1529 | - |
1530 | - """This sets the terminal window size of the child tty. This will cause |
1531 | - a SIGWINCH signal to be sent to the child. This does not change the |
1532 | - physical window size. It changes the size reported to TTY-aware |
1533 | - applications like vi or curses -- applications that respond to the |
1534 | - SIGWINCH signal. """ |
1535 | - |
1536 | - # Check for buggy platforms. Some Python versions on some platforms |
1537 | - # (notably OSF1 Alpha and RedHat 7.1) truncate the value for |
1538 | - # termios.TIOCSWINSZ. It is not clear why this happens. |
1539 | - # These platforms don't seem to handle the signed int very well; |
1540 | - # yet other platforms like OpenBSD have a large negative value for |
1541 | - # TIOCSWINSZ and they don't have a truncate problem. |
1542 | - # Newer versions of Linux have totally different values for TIOCSWINSZ. |
1543 | - # Note that this fix is a hack. |
1544 | - TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561) |
1545 | - if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2. |
1546 | - TIOCSWINSZ = -2146929561 # Same bits, but with sign. |
1547 | - # Note, assume ws_xpixel and ws_ypixel are zero. |
1548 | - s = struct.pack('HHHH', r, c, 0, 0) |
1549 | - fcntl.ioctl(self.fileno(), TIOCSWINSZ, s) |
1550 | - |
1551 | - def interact(self, escape_character = chr(29), input_filter = None, output_filter = None): |
1552 | - |
1553 | - """This gives control of the child process to the interactive user (the |
1554 | - human at the keyboard). Keystrokes are sent to the child process, and |
1555 | - the stdout and stderr output of the child process is printed. This |
1556 | - simply echos the child stdout and child stderr to the real stdout and |
1557 | - it echos the real stdin to the child stdin. When the user types the |
1558 | - escape_character this method will stop. The default for |
1559 | - escape_character is ^]. This should not be confused with ASCII 27 -- |
1560 | - the ESC character. ASCII 29 was chosen for historical merit because |
1561 | - this is the character used by 'telnet' as the escape character. The |
1562 | - escape_character will not be sent to the child process. |
1563 | - |
1564 | - You may pass in optional input and output filter functions. These |
1565 | - functions should take a string and return a string. The output_filter |
1566 | - will be passed all the output from the child process. The input_filter |
1567 | - will be passed all the keyboard input from the user. The input_filter |
1568 | - is run BEFORE the check for the escape_character. |
1569 | - |
1570 | - Note that if you change the window size of the parent the SIGWINCH |
1571 | - signal will not be passed through to the child. If you want the child |
1572 | - window size to change when the parent's window size changes then do |
1573 | - something like the following example:: |
1574 | - |
1575 | - import pexpect, struct, fcntl, termios, signal, sys |
1576 | - def sigwinch_passthrough (sig, data): |
1577 | - s = struct.pack("HHHH", 0, 0, 0, 0) |
1578 | - a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s)) |
1579 | - global p |
1580 | - p.setwinsize(a[0],a[1]) |
1581 | - p = pexpect.spawn('/bin/bash') # Note this is global and used in sigwinch_passthrough. |
1582 | - signal.signal(signal.SIGWINCH, sigwinch_passthrough) |
1583 | - p.interact() |
1584 | - """ |
1585 | - |
1586 | - # Flush the buffer. |
1587 | - self.stdout.write (self.buffer) |
1588 | - self.stdout.flush() |
1589 | - self.buffer = '' |
1590 | - mode = tty.tcgetattr(self.STDIN_FILENO) |
1591 | - tty.setraw(self.STDIN_FILENO) |
1592 | - try: |
1593 | - self.__interact_copy(escape_character, input_filter, output_filter) |
1594 | - finally: |
1595 | - tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode) |
1596 | - |
1597 | - def __interact_writen(self, fd, data): |
1598 | - |
1599 | - """This is used by the interact() method. |
1600 | - """ |
1601 | - |
1602 | - while data != '' and self.isalive(): |
1603 | - n = os.write(fd, data) |
1604 | - data = data[n:] |
1605 | - |
1606 | - def __interact_read(self, fd): |
1607 | - |
1608 | - """This is used by the interact() method. |
1609 | - """ |
1610 | - |
1611 | - return os.read(fd, 1000) |
1612 | - |
1613 | - def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None): |
1614 | - |
1615 | - """This is used by the interact() method. |
1616 | - """ |
1617 | - |
1618 | - while self.isalive(): |
1619 | - r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], []) #@UnusedVariable |
1620 | - if self.child_fd in r: |
1621 | - data = self.__interact_read(self.child_fd) |
1622 | - if output_filter: data = output_filter(data) |
1623 | - if self.logfile is not None: |
1624 | - self.logfile.write (data) |
1625 | - self.logfile.flush() |
1626 | - os.write(self.STDOUT_FILENO, data) |
1627 | - if self.STDIN_FILENO in r: |
1628 | - data = self.__interact_read(self.STDIN_FILENO) |
1629 | - if input_filter: data = input_filter(data) |
1630 | - i = data.rfind(escape_character) |
1631 | - if i != -1: |
1632 | - data = data[:i] |
1633 | - self.__interact_writen(self.child_fd, data) |
1634 | - break |
1635 | - self.__interact_writen(self.child_fd, data) |
1636 | - |
1637 | - def __select (self, iwtd, owtd, ewtd, timeout=None): |
1638 | - |
1639 | - """This is a wrapper around select.select() that ignores signals. If |
1640 | - select.select raises a select.error exception and errno is an EINTR |
1641 | - error then it is ignored. Mainly this is used to ignore sigwinch |
1642 | - (terminal resize). """ |
1643 | - |
1644 | - # if select() is interrupted by a signal (errno==EINTR) then |
1645 | - # we loop back and enter the select() again. |
1646 | - if timeout is not None: |
1647 | - end_time = time.time() + timeout |
1648 | - while True: |
1649 | - try: |
1650 | - return select.select (iwtd, owtd, ewtd, timeout) |
1651 | - except select.error, e: |
1652 | - if e[0] == errno.EINTR: |
1653 | - # if we loop back we have to subtract the amount of time we already waited. |
1654 | - if timeout is not None: |
1655 | - timeout = end_time - time.time() |
1656 | - if timeout < 0: |
1657 | - return ([],[],[]) |
1658 | - else: # something else caused the select.error, so this really is an exception |
1659 | - raise |
1660 | - |
1661 | -############################################################################## |
1662 | -# The following methods are no longer supported or allowed. |
1663 | - |
1664 | - def setmaxread (self, maxread): |
1665 | - |
1666 | - """This method is no longer supported or allowed. I don't like getters |
1667 | - and setters without a good reason. """ |
1668 | - |
1669 | - raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the maxread member variable.') |
1670 | - |
1671 | - def setlog (self, fileobject): |
1672 | - |
1673 | - """This method is no longer supported or allowed. |
1674 | - """ |
1675 | - |
1676 | - raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the logfile member variable.') |
1677 | - |
1678 | -############################################################################## |
1679 | -# End of spawn class |
1680 | -############################################################################## |
1681 | - |
1682 | -class searcher_string (object): |
1683 | - |
1684 | - """This is a plain string search helper for the spawn.expect_any() method. |
1685 | - |
1686 | - Attributes: |
1687 | - |
1688 | - eof_index - index of EOF, or -1 |
1689 | - timeout_index - index of TIMEOUT, or -1 |
1690 | - |
1691 | - After a successful match by the search() method the following attributes |
1692 | - are available: |
1693 | - |
1694 | - start - index into the buffer, first byte of match |
1695 | - end - index into the buffer, first byte after match |
1696 | - match - the matching string itself |
1697 | - """ |
1698 | - |
1699 | - def __init__(self, strings): |
1700 | - |
1701 | - """This creates an instance of searcher_string. This argument 'strings' |
1702 | - may be a list; a sequence of strings; or the EOF or TIMEOUT types. """ |
1703 | - |
1704 | - self.eof_index = -1 |
1705 | - self.timeout_index = -1 |
1706 | - self._strings = [] |
1707 | - for n, s in zip(range(len(strings)), strings): |
1708 | - if s is EOF: |
1709 | - self.eof_index = n |
1710 | - continue |
1711 | - if s is TIMEOUT: |
1712 | - self.timeout_index = n |
1713 | - continue |
1714 | - self._strings.append((n, s)) |
1715 | - |
1716 | - def __str__(self): |
1717 | - |
1718 | - """This returns a human-readable string that represents the state of |
1719 | - the object.""" |
1720 | - |
1721 | - ss = [ (ns[0],' %d: "%s"' % ns) for ns in self._strings ] |
1722 | - ss.append((-1,'searcher_string:')) |
1723 | - if self.eof_index >= 0: |
1724 | - ss.append ((self.eof_index,' %d: EOF' % self.eof_index)) |
1725 | - if self.timeout_index >= 0: |
1726 | - ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index)) |
1727 | - ss.sort() |
1728 | - ss = zip(*ss)[1] |
1729 | - return '\n'.join(ss) |
1730 | - |
1731 | - def search(self, buffer, freshlen, searchwindowsize=None): |
1732 | - |
1733 | - """This searches 'buffer' for the first occurence of one of the search |
1734 | - strings. 'freshlen' must indicate the number of bytes at the end of |
1735 | - 'buffer' which have not been searched before. It helps to avoid |
1736 | - searching the same, possibly big, buffer over and over again. |
1737 | - |
1738 | - See class spawn for the 'searchwindowsize' argument. |
1739 | - |
1740 | - If there is a match this returns the index of that string, and sets |
1741 | - 'start', 'end' and 'match'. Otherwise, this returns -1. """ |
1742 | - |
1743 | - absurd_match = len(buffer) |
1744 | - first_match = absurd_match |
1745 | - |
1746 | - # 'freshlen' helps a lot here. Further optimizations could |
1747 | - # possibly include: |
1748 | - # |
1749 | - # using something like the Boyer-Moore Fast String Searching |
1750 | - # Algorithm; pre-compiling the search through a list of |
1751 | - # strings into something that can scan the input once to |
1752 | - # search for all N strings; realize that if we search for |
1753 | - # ['bar', 'baz'] and the input is '...foo' we need not bother |
1754 | - # rescanning until we've read three more bytes. |
1755 | - # |
1756 | - # Sadly, I don't know enough about this interesting topic. /grahn |
1757 | - |
1758 | - for index, s in self._strings: |
1759 | - if searchwindowsize is None: |
1760 | - # the match, if any, can only be in the fresh data, |
1761 | - # or at the very end of the old data |
1762 | - offset = -(freshlen+len(s)) |
1763 | - else: |
1764 | - # better obey searchwindowsize |
1765 | - offset = -searchwindowsize |
1766 | - n = buffer.find(s, offset) |
1767 | - if n >= 0 and n < first_match: |
1768 | - first_match = n |
1769 | - best_index, best_match = index, s |
1770 | - if first_match == absurd_match: |
1771 | - return -1 |
1772 | - self.match = best_match |
1773 | - self.start = first_match |
1774 | - self.end = self.start + len(self.match) |
1775 | - return best_index |
1776 | - |
1777 | -class searcher_re (object): |
1778 | - |
1779 | - """This is regular expression string search helper for the |
1780 | - spawn.expect_any() method. |
1781 | - |
1782 | - Attributes: |
1783 | - |
1784 | - eof_index - index of EOF, or -1 |
1785 | - timeout_index - index of TIMEOUT, or -1 |
1786 | - |
1787 | - After a successful match by the search() method the following attributes |
1788 | - are available: |
1789 | - |
1790 | - start - index into the buffer, first byte of match |
1791 | - end - index into the buffer, first byte after match |
1792 | - match - the re.match object returned by a succesful re.search |
1793 | - |
1794 | - """ |
1795 | - |
1796 | - def __init__(self, patterns): |
1797 | - |
1798 | - """This creates an instance that searches for 'patterns' Where |
1799 | - 'patterns' may be a list or other sequence of compiled regular |
1800 | - expressions, or the EOF or TIMEOUT types.""" |
1801 | - |
1802 | - self.eof_index = -1 |
1803 | - self.timeout_index = -1 |
1804 | - self._searches = [] |
1805 | - for n, s in zip(range(len(patterns)), patterns): |
1806 | - if s is EOF: |
1807 | - self.eof_index = n |
1808 | - continue |
1809 | - if s is TIMEOUT: |
1810 | - self.timeout_index = n |
1811 | - continue |
1812 | - self._searches.append((n, s)) |
1813 | - |
1814 | - def __str__(self): |
1815 | - |
1816 | - """This returns a human-readable string that represents the state of |
1817 | - the object.""" |
1818 | - |
1819 | - ss = [ (n,' %d: re.compile("%s")' % (n,str(s.pattern))) for n,s in self._searches] |
1820 | - ss.append((-1,'searcher_re:')) |
1821 | - if self.eof_index >= 0: |
1822 | - ss.append ((self.eof_index,' %d: EOF' % self.eof_index)) |
1823 | - if self.timeout_index >= 0: |
1824 | - ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index)) |
1825 | - ss.sort() |
1826 | - ss = zip(*ss)[1] |
1827 | - return '\n'.join(ss) |
1828 | - |
1829 | - def search(self, buffer, freshlen, searchwindowsize=None): |
1830 | - |
1831 | - """This searches 'buffer' for the first occurence of one of the regular |
1832 | - expressions. 'freshlen' must indicate the number of bytes at the end of |
1833 | - 'buffer' which have not been searched before. |
1834 | - |
1835 | - See class spawn for the 'searchwindowsize' argument. |
1836 | - |
1837 | - If there is a match this returns the index of that string, and sets |
1838 | - 'start', 'end' and 'match'. Otherwise, returns -1.""" |
1839 | - |
1840 | - absurd_match = len(buffer) |
1841 | - first_match = absurd_match |
1842 | - # 'freshlen' doesn't help here -- we cannot predict the |
1843 | - # length of a match, and the re module provides no help. |
1844 | - if searchwindowsize is None: |
1845 | - searchstart = 0 |
1846 | - else: |
1847 | - searchstart = max(0, len(buffer)-searchwindowsize) |
1848 | - for index, s in self._searches: |
1849 | - match = s.search(buffer, searchstart) |
1850 | - if match is None: |
1851 | - continue |
1852 | - n = match.start() |
1853 | - if n < first_match: |
1854 | - first_match = n |
1855 | - the_match = match |
1856 | - best_index = index |
1857 | - if first_match == absurd_match: |
1858 | - return -1 |
1859 | - self.start = first_match |
1860 | - self.match = the_match |
1861 | - self.end = self.match.end() |
1862 | - return best_index |
1863 | - |
1864 | -def which (filename): |
1865 | - |
1866 | - """This takes a given filename; tries to find it in the environment path; |
1867 | - then checks if it is executable. This returns the full path to the filename |
1868 | - if found and executable. Otherwise this returns None.""" |
1869 | - |
1870 | - # Special case where filename already contains a path. |
1871 | - if os.path.dirname(filename) != '': |
1872 | - if os.access (filename, os.X_OK): |
1873 | - return filename |
1874 | - |
1875 | - if not os.environ.has_key('PATH') or os.environ['PATH'] == '': |
1876 | - p = os.defpath |
1877 | - else: |
1878 | - p = os.environ['PATH'] |
1879 | - |
1880 | - # Oddly enough this was the one line that made Pexpect |
1881 | - # incompatible with Python 1.5.2. |
1882 | - #pathlist = p.split (os.pathsep) |
1883 | - pathlist = string.split (p, os.pathsep) |
1884 | - |
1885 | - for path in pathlist: |
1886 | - f = os.path.join(path, filename) |
1887 | - if os.access(f, os.X_OK): |
1888 | - return f |
1889 | - return None |
1890 | - |
1891 | -def split_command_line(command_line): |
1892 | - |
1893 | - """This splits a command line into a list of arguments. It splits arguments |
1894 | - on spaces, but handles embedded quotes, doublequotes, and escaped |
1895 | - characters. It's impossible to do this with a regular expression, so I |
1896 | - wrote a little state machine to parse the command line. """ |
1897 | - |
1898 | - arg_list = [] |
1899 | - arg = '' |
1900 | - |
1901 | - # Constants to name the states we can be in. |
1902 | - state_basic = 0 |
1903 | - state_esc = 1 |
1904 | - state_singlequote = 2 |
1905 | - state_doublequote = 3 |
1906 | - state_whitespace = 4 # The state of consuming whitespace between commands. |
1907 | - state = state_basic |
1908 | - |
1909 | - for c in command_line: |
1910 | - if state == state_basic or state == state_whitespace: |
1911 | - if c == '\\': # Escape the next character |
1912 | - state = state_esc |
1913 | - elif c == r"'": # Handle single quote |
1914 | - state = state_singlequote |
1915 | - elif c == r'"': # Handle double quote |
1916 | - state = state_doublequote |
1917 | - elif c.isspace(): |
1918 | - # Add arg to arg_list if we aren't in the middle of whitespace. |
1919 | - if state == state_whitespace: |
1920 | - None # Do nothing. |
1921 | - else: |
1922 | - arg_list.append(arg) |
1923 | - arg = '' |
1924 | - state = state_whitespace |
1925 | - else: |
1926 | - arg = arg + c |
1927 | - state = state_basic |
1928 | - elif state == state_esc: |
1929 | - arg = arg + c |
1930 | - state = state_basic |
1931 | - elif state == state_singlequote: |
1932 | - if c == r"'": |
1933 | - state = state_basic |
1934 | - else: |
1935 | - arg = arg + c |
1936 | - elif state == state_doublequote: |
1937 | - if c == r'"': |
1938 | - state = state_basic |
1939 | - else: |
1940 | - arg = arg + c |
1941 | - |
1942 | - if arg != '': |
1943 | - arg_list.append(arg) |
1944 | - return arg_list |
1945 | - |
1946 | -# vi:ts=4:sw=4:expandtab:ft=python: |
1947 | |
1948 | === modified file 'po/POTFILES.in' |
1949 | --- po/POTFILES.in 2014-04-17 19:53:39 +0000 |
1950 | +++ po/POTFILES.in 2014-04-17 19:53:39 +0000 |
1951 | @@ -51,7 +51,6 @@ |
1952 | duplicity/filechunkio.py |
1953 | duplicity/dup_threading.py |
1954 | duplicity/path.py |
1955 | -duplicity/pexpect.py |
1956 | duplicity/gpginterface.py |
1957 | duplicity/dup_time.py |
1958 | duplicity/gpg.py |
1959 | |
1960 | === modified file 'setup.py' |
1961 | --- setup.py 2014-04-16 20:45:09 +0000 |
1962 | +++ setup.py 2014-04-17 19:53:39 +0000 |
1963 | @@ -144,7 +144,7 @@ |
1964 | libraries=["rsync"])], |
1965 | scripts = ['bin/rdiffdir', 'bin/duplicity'], |
1966 | data_files = data_files, |
1967 | - tests_require = ['lockfile', 'mock', 'nose'], |
1968 | + tests_require = ['lockfile', 'mock', 'nose', 'pexpect'], |
1969 | test_suite = 'nose.collector', |
1970 | cmdclass={'test': TestCommand, |
1971 | 'install': InstallCommand, |
1972 | |
1973 | === modified file 'testing/helpers/helper.py' |
1974 | --- testing/helpers/helper.py 2014-04-16 02:43:43 +0000 |
1975 | +++ testing/helpers/helper.py 2014-04-17 19:53:39 +0000 |
1976 | @@ -20,13 +20,13 @@ |
1977 | # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1978 | |
1979 | import os |
1980 | +import pexpect |
1981 | import time |
1982 | import unittest |
1983 | |
1984 | from duplicity import backend |
1985 | from duplicity import globals |
1986 | from duplicity import log |
1987 | -from duplicity import pexpect |
1988 | |
1989 | sign_key = '56538CCF' |
1990 | sign_passphrase = 'test' |
1991 | |
1992 | === modified file 'tox.ini' |
1993 | --- tox.ini 2014-04-16 18:37:39 +0000 |
1994 | +++ tox.ini 2014-04-17 19:53:39 +0000 |
1995 | @@ -5,4 +5,5 @@ |
1996 | deps=lockfile |
1997 | mock |
1998 | nose |
1999 | + pexpect |
2000 | commands=nosetests |
Mike,
could you please check if the par backend still works, as it seems to be affected as well?
thx.. ede