Merge lp:~mterry/duplicity/drop-pexpect into lp:duplicity/0.6

Proposed by Michael Terry
Status: Superseded
Proposed branch: lp:~mterry/duplicity/drop-pexpect
Merge into: lp:duplicity/0.6
Diff against target: 2162 lines (+52/-1903)
9 files modified
bin/duplicity.1 (+3/-0)
duplicity/backend.py (+39/-49)
duplicity/backends/_ssh_pexpect.py (+2/-1)
duplicity/backends/~par2wrapperbackend.py (+5/-4)
duplicity/pexpect.py (+0/-1845)
po/POTFILES.in (+0/-2)
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
Reviewer Review Type Date Requested Status
duplicity-team Pending
Review via email: mp+216388@code.launchpad.net

This proposal has been superseded by a proposal from 2014-04-17.

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=pexpect) and it seemed to work fine with a modern version of pexpect.

To post a comment you must log in.
lp:~mterry/duplicity/drop-pexpect updated
975. By Michael Terry

fix typo

Unmerged revisions

Preview Diff

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

Subscribers

People subscribed via source and target branches

to all changes: