| Index: third_party/pexpect/pexpect/expect.py
|
| diff --git a/third_party/pexpect/pexpect/expect.py b/third_party/pexpect/pexpect/expect.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6fde9e8241db3ad3d3f1858cb3604422a3fdf862
|
| --- /dev/null
|
| +++ b/third_party/pexpect/pexpect/expect.py
|
| @@ -0,0 +1,297 @@
|
| +import time
|
| +
|
| +from .exceptions import EOF, TIMEOUT
|
| +
|
| +class Expecter(object):
|
| + def __init__(self, spawn, searcher, searchwindowsize=-1):
|
| + self.spawn = spawn
|
| + self.searcher = searcher
|
| + if searchwindowsize == -1:
|
| + searchwindowsize = spawn.searchwindowsize
|
| + self.searchwindowsize = searchwindowsize
|
| +
|
| + def new_data(self, data):
|
| + spawn = self.spawn
|
| + searcher = self.searcher
|
| +
|
| + incoming = spawn.buffer + data
|
| + freshlen = len(data)
|
| + index = searcher.search(incoming, freshlen, self.searchwindowsize)
|
| + if index >= 0:
|
| + spawn.buffer = incoming[searcher.end:]
|
| + spawn.before = incoming[: searcher.start]
|
| + spawn.after = incoming[searcher.start: searcher.end]
|
| + spawn.match = searcher.match
|
| + spawn.match_index = index
|
| + # Found a match
|
| + return index
|
| +
|
| + spawn.buffer = incoming
|
| +
|
| + def eof(self, err=None):
|
| + spawn = self.spawn
|
| + from . import EOF
|
| +
|
| + spawn.before = spawn.buffer
|
| + spawn.buffer = spawn.string_type()
|
| + spawn.after = EOF
|
| + index = self.searcher.eof_index
|
| + if index >= 0:
|
| + spawn.match = EOF
|
| + spawn.match_index = index
|
| + return index
|
| + else:
|
| + spawn.match = None
|
| + spawn.match_index = None
|
| + msg = str(spawn)
|
| + if err is not None:
|
| + msg = str(err) + '\n' + msg
|
| + raise EOF(msg)
|
| +
|
| + def timeout(self, err=None):
|
| + spawn = self.spawn
|
| + from . import TIMEOUT
|
| +
|
| + spawn.before = spawn.buffer
|
| + spawn.after = TIMEOUT
|
| + index = self.searcher.timeout_index
|
| + if index >= 0:
|
| + spawn.match = TIMEOUT
|
| + spawn.match_index = index
|
| + return index
|
| + else:
|
| + spawn.match = None
|
| + spawn.match_index = None
|
| + msg = str(spawn)
|
| + if err is not None:
|
| + msg = str(err) + '\n' + msg
|
| + raise TIMEOUT(msg)
|
| +
|
| + def errored(self):
|
| + spawn = self.spawn
|
| + spawn.before = spawn.buffer
|
| + spawn.after = None
|
| + spawn.match = None
|
| + spawn.match_index = None
|
| +
|
| + def expect_loop(self, timeout=-1):
|
| + """Blocking expect"""
|
| + spawn = self.spawn
|
| + from . import EOF, TIMEOUT
|
| +
|
| + if timeout is not None:
|
| + end_time = time.time() + timeout
|
| +
|
| + try:
|
| + incoming = spawn.buffer
|
| + spawn.buffer = spawn.string_type() # Treat buffer as new data
|
| + while True:
|
| + idx = self.new_data(incoming)
|
| + # Keep reading until exception or return.
|
| + if idx is not None:
|
| + return idx
|
| + # No match at this point
|
| + if (timeout is not None) and (timeout < 0):
|
| + return self.timeout()
|
| + # Still have time left, so read more data
|
| + incoming = spawn.read_nonblocking(spawn.maxread, timeout)
|
| + time.sleep(0.0001)
|
| + if timeout is not None:
|
| + timeout = end_time - time.time()
|
| + except EOF as e:
|
| + return self.eof(e)
|
| + except TIMEOUT as e:
|
| + return self.timeout(e)
|
| + except:
|
| + self.errored()
|
| + raise
|
| +
|
| +
|
| +class searcher_string(object):
|
| + '''This is a plain string search helper for the spawn.expect_any() method.
|
| + This helper class is for speed. For more powerful regex patterns
|
| + see the helper class, searcher_re.
|
| +
|
| + Attributes:
|
| +
|
| + eof_index - index of EOF, or -1
|
| + timeout_index - index of TIMEOUT, or -1
|
| +
|
| + After a successful match by the search() method the following attributes
|
| + are available:
|
| +
|
| + start - index into the buffer, first byte of match
|
| + end - index into the buffer, first byte after match
|
| + match - the matching string itself
|
| +
|
| + '''
|
| +
|
| + def __init__(self, strings):
|
| + '''This creates an instance of searcher_string. This argument 'strings'
|
| + may be a list; a sequence of strings; or the EOF or TIMEOUT types. '''
|
| +
|
| + self.eof_index = -1
|
| + self.timeout_index = -1
|
| + self._strings = []
|
| + for n, s in enumerate(strings):
|
| + if s is EOF:
|
| + self.eof_index = n
|
| + continue
|
| + if s is TIMEOUT:
|
| + self.timeout_index = n
|
| + continue
|
| + self._strings.append((n, s))
|
| +
|
| + def __str__(self):
|
| + '''This returns a human-readable string that represents the state of
|
| + the object.'''
|
| +
|
| + ss = [(ns[0], ' %d: "%s"' % ns) for ns in self._strings]
|
| + ss.append((-1, 'searcher_string:'))
|
| + if self.eof_index >= 0:
|
| + ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
|
| + if self.timeout_index >= 0:
|
| + ss.append((self.timeout_index,
|
| + ' %d: TIMEOUT' % self.timeout_index))
|
| + ss.sort()
|
| + ss = list(zip(*ss))[1]
|
| + return '\n'.join(ss)
|
| +
|
| + def search(self, buffer, freshlen, searchwindowsize=None):
|
| + '''This searches 'buffer' for the first occurence of one of the search
|
| + strings. 'freshlen' must indicate the number of bytes at the end of
|
| + 'buffer' which have not been searched before. It helps to avoid
|
| + searching the same, possibly big, buffer over and over again.
|
| +
|
| + See class spawn for the 'searchwindowsize' argument.
|
| +
|
| + If there is a match this returns the index of that string, and sets
|
| + 'start', 'end' and 'match'. Otherwise, this returns -1. '''
|
| +
|
| + first_match = None
|
| +
|
| + # 'freshlen' helps a lot here. Further optimizations could
|
| + # possibly include:
|
| + #
|
| + # using something like the Boyer-Moore Fast String Searching
|
| + # Algorithm; pre-compiling the search through a list of
|
| + # strings into something that can scan the input once to
|
| + # search for all N strings; realize that if we search for
|
| + # ['bar', 'baz'] and the input is '...foo' we need not bother
|
| + # rescanning until we've read three more bytes.
|
| + #
|
| + # Sadly, I don't know enough about this interesting topic. /grahn
|
| +
|
| + for index, s in self._strings:
|
| + if searchwindowsize is None:
|
| + # the match, if any, can only be in the fresh data,
|
| + # or at the very end of the old data
|
| + offset = -(freshlen + len(s))
|
| + else:
|
| + # better obey searchwindowsize
|
| + offset = -searchwindowsize
|
| + n = buffer.find(s, offset)
|
| + if n >= 0 and (first_match is None or n < first_match):
|
| + first_match = n
|
| + best_index, best_match = index, s
|
| + if first_match is None:
|
| + return -1
|
| + self.match = best_match
|
| + self.start = first_match
|
| + self.end = self.start + len(self.match)
|
| + return best_index
|
| +
|
| +
|
| +class searcher_re(object):
|
| + '''This is regular expression string search helper for the
|
| + spawn.expect_any() method. This helper class is for powerful
|
| + pattern matching. For speed, see the helper class, searcher_string.
|
| +
|
| + Attributes:
|
| +
|
| + eof_index - index of EOF, or -1
|
| + timeout_index - index of TIMEOUT, or -1
|
| +
|
| + After a successful match by the search() method the following attributes
|
| + are available:
|
| +
|
| + start - index into the buffer, first byte of match
|
| + end - index into the buffer, first byte after match
|
| + match - the re.match object returned by a succesful re.search
|
| +
|
| + '''
|
| +
|
| + def __init__(self, patterns):
|
| + '''This creates an instance that searches for 'patterns' Where
|
| + 'patterns' may be a list or other sequence of compiled regular
|
| + expressions, or the EOF or TIMEOUT types.'''
|
| +
|
| + self.eof_index = -1
|
| + self.timeout_index = -1
|
| + self._searches = []
|
| + for n, s in zip(list(range(len(patterns))), patterns):
|
| + if s is EOF:
|
| + self.eof_index = n
|
| + continue
|
| + if s is TIMEOUT:
|
| + self.timeout_index = n
|
| + continue
|
| + self._searches.append((n, s))
|
| +
|
| + def __str__(self):
|
| + '''This returns a human-readable string that represents the state of
|
| + the object.'''
|
| +
|
| + #ss = [(n, ' %d: re.compile("%s")' %
|
| + # (n, repr(s.pattern))) for n, s in self._searches]
|
| + ss = list()
|
| + for n, s in self._searches:
|
| + try:
|
| + ss.append((n, ' %d: re.compile("%s")' % (n, s.pattern)))
|
| + except UnicodeEncodeError:
|
| + # for test cases that display __str__ of searches, dont throw
|
| + # another exception just because stdout is ascii-only, using
|
| + # repr()
|
| + ss.append((n, ' %d: re.compile(%r)' % (n, s.pattern)))
|
| + ss.append((-1, 'searcher_re:'))
|
| + if self.eof_index >= 0:
|
| + ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
|
| + if self.timeout_index >= 0:
|
| + ss.append((self.timeout_index, ' %d: TIMEOUT' %
|
| + self.timeout_index))
|
| + ss.sort()
|
| + ss = list(zip(*ss))[1]
|
| + return '\n'.join(ss)
|
| +
|
| + def search(self, buffer, freshlen, searchwindowsize=None):
|
| + '''This searches 'buffer' for the first occurence of one of the regular
|
| + expressions. 'freshlen' must indicate the number of bytes at the end of
|
| + 'buffer' which have not been searched before.
|
| +
|
| + See class spawn for the 'searchwindowsize' argument.
|
| +
|
| + If there is a match this returns the index of that string, and sets
|
| + 'start', 'end' and 'match'. Otherwise, returns -1.'''
|
| +
|
| + first_match = None
|
| + # 'freshlen' doesn't help here -- we cannot predict the
|
| + # length of a match, and the re module provides no help.
|
| + if searchwindowsize is None:
|
| + searchstart = 0
|
| + else:
|
| + searchstart = max(0, len(buffer) - searchwindowsize)
|
| + for index, s in self._searches:
|
| + match = s.search(buffer, searchstart)
|
| + if match is None:
|
| + continue
|
| + n = match.start()
|
| + if first_match is None or n < first_match:
|
| + first_match = n
|
| + the_match = match
|
| + best_index = index
|
| + if first_match is None:
|
| + return -1
|
| + self.start = first_match
|
| + self.match = the_match
|
| + self.end = self.match.end()
|
| + return best_index
|
|
|