def expect_ftcs_command_finished(zsh: pexpect.spawn) -> typing.Optional[int]: """Match a FinalTerm FTCS_COMMAND_FINISHED escape sequence. """ zsh.expect( b"\x1b]133;D(?:;(?P<exit_status>[0-9]+))?" + ftcs_extra_arguments_re + b"\x07" ) exit_status = zsh.match.group("exit_status") if not exit_status: return None return int(exit_status)
def assert_bash_exec( bash: pexpect.spawn, cmd: str, want_output: bool = False) -> str: # Send command bash.sendline(cmd) bash.expect_exact(cmd) # Find prompt, output is before it bash.expect_exact("\r\n" + PS1) output = bash.before # Retrieve exit status echo = "echo $?" bash.sendline(echo) got = bash.expect([ r"^%s\r\n(\d+)\r\n%s" % (re.escape(echo), re.escape(PS1)), PS1, pexpect.EOF, pexpect.TIMEOUT, ]) status = bash.match.group(1) if got == 0 else "unknown" assert status == "0", \ 'Error running "%s": exit status=%s, output="%s"' % \ (cmd, status, output) if output: assert want_output, \ 'Unexpected output from "%s": exit status=%s, output="%s"' % \ (cmd, status, output) else: assert not want_output, \ 'Expected output from "%s": exit status=%s, output="%s"' % \ (cmd, status, output) return output
def spawnAction(self, sp: spawn): keys = list(self.keys()) r = sp.expect(keys) yield r matched = keys[r] print('received {} ({})'.format(matched, r)) yield from self.get(matched).spawnAction(sp)
def is_bash_type(bash: pexpect.spawn, cmd: str) -> bool: typecmd = "type %s &>/dev/null && echo -n 0 || echo -n 1" % cmd bash.sendline(typecmd) bash.expect_exact(typecmd + "\r\n") result = bash.expect_exact(["0", "1"]) == 0 bash.expect_exact(PS1) return result
def execute(self, sp: spawn, outputhook=print): gen = self.seq.spawnAction(sp) try: self.last = next(gen) while True: args = self.log(sp, outputhook) self.last = gen.send(args) except StopIteration: r = sp.expect([EOF, TIMEOUT]) self.log(sp, outputhook) if r: self.error(sp.command) except (TIMEOUT, EOF) as e: self.log(sp, outputhook) self.error(sp.command) raise e return self
def expect_ftcs_command_executed(zsh: pexpect.spawn) -> None: """Match a FinalTerm FTCS_COMMAND_EXECUTED escape sequence. """ zsh.expect(b"\x1b]133;C" + ftcs_extra_arguments_re + b"\x07")
def expect_ftcs_command_start(zsh: pexpect.spawn) -> None: """Match a FinalTerm FTCS_COMMAND_START escape sequence. """ zsh.expect(b"\x1b]133;B" + ftcs_extra_arguments_re + b"\x07")
def expect_ftcs_prompt(zsh: pexpect.spawn) -> None: """Match a FinalTerm FTCS_PROMPT escape sequence. """ zsh.expect(b"\x1b]133;A" + ftcs_extra_arguments_re + b"\x07")
def connect(self, connection=None): """ See :meth:`BaseShell.connect` for more information. """ connection = connection or self._default_connection or '0' if connection in self._connections and self.is_connected(connection): raise AlreadyConnectedError(connection) # Inject framework logger to the spawn object spawn_args = { 'logfile': get_logger( OrderedDict([ ('node_identifier', self._node_identifier), ('shell_name', self._shell_name), ('connection', connection) ]), category='pexpect' ), } # Create a child process spawn_args.update(self._spawn_args) spawn = Spawn( self._get_connect_command().strip(), **spawn_args ) # Add a connection logger # Note: self._node and self._name were added to this shell in the # node's call to its _register_shell method. spawn._connection_logger = get_logger( OrderedDict([ ('node_identifier', self._node_identifier), ('shell_name', self._shell_name), ('connection', connection) ]), category='connection' ) self._connections[connection] = spawn try: # If connection is via user if self._user is not None: spawn.expect( [self._user_match], timeout=self._timeout ) spawn.sendline(self._user) # If connection is via password if self._password is not None: spawn.expect( [self._password_match], timeout=self._timeout ) spawn.sendline(self._password) # Setup shell before using it self._setup_shell(connection) # Execute initial command if required if self._initial_command is not None: spawn.expect( self._prompt, timeout=self._timeout ) spawn.sendline(self._initial_command) # Wait for command response to match the prompt spawn.expect( self._prompt, timeout=self._timeout ) except: # Always remove bad connections if it failed del self._connections[connection] raise # Set connection as default connection if required if self.default_connection is None: self.default_connection = connection
def spawnAction(self, sp: spawn): print("sendline {}".format(self)) yield sp.sendline(self)
def wait_for_pexpect_process(process: pexpect.spawn) -> int: process.expect_exact(pexpect.EOF) return process.wait()
def send_and_expect_byte_by_byte(zsh: pexpect.spawn, input: bytes) -> bytes: for byte in input: current_input = bytes([byte]) zsh.send(current_input) zsh.expect(string_ignoring_escape_sequences_re(current_input))
def assert_complete( bash: pexpect.spawn, cmd: str, **kwargs) -> CompletionResult: skipif = kwargs.get("skipif") if skipif: try: assert_bash_exec(bash, skipif) except AssertionError: pass else: pytest.skip(skipif) return CompletionResult("", []) cwd = kwargs.get("cwd") if cwd: assert_bash_exec(bash, "cd '%s'" % cwd) env_prefix = "_BASHCOMP_TEST_" env = kwargs.get("env", {}) if env: # Back up environment and apply new one assert_bash_exec(bash, " ".join( '%s%s="$%s"' % (env_prefix, k, k) for k in env.keys() )) assert_bash_exec(bash, "export %s" % " ".join( "%s=%s" % (k, v) for k, v in env.items() )) bash.send(cmd + "\t") bash.expect_exact(cmd) bash.send(MAGIC_MARK) got = bash.expect([ r"\r\n" + re.escape(PS1 + cmd), # 0: multiple lines, result in .before r"^" + MAGIC_MARK, # 1: no completion r"^[^\r]+", # 2: on same line, result in .after pexpect.EOF, pexpect.TIMEOUT, ]) if got == 0: line = bash.before if line.endswith(MAGIC_MARK): line = bash.before[:-len(MAGIC_MARK)] result = CompletionResult( line, sorted(x for x in re.split(r" {2,}|\r\n", line) if x), ) elif got == 2: line = bash.after if line.endswith(MAGIC_MARK): line = bash.after[:-len(MAGIC_MARK)] result = CompletionResult( line, [shlex.split(cmd + line)[-1]], ) else: # TODO: warn about EOF/TIMEOUT? result = CompletionResult("", []) bash.sendintr() bash.expect_exact(PS1) if env: # Restore environment, and clean up backup # TODO: Test with declare -p if a var was set, backup only if yes, and # similarly restore only backed up vars. Should remove some need # for ignore_env. assert_bash_exec(bash, "export %s" % " ".join( '%s="$%s%s"' % (k, env_prefix, k) for k in env.keys() )) assert_bash_exec(bash, "unset -v %s" % " ".join( "%s%s" % (env_prefix, k) for k in env.keys() )) if cwd: assert_bash_exec(bash, "cd - >/dev/null") return result
def assert_complete(bash: pexpect.spawn, cmd: str, **kwargs) -> CompletionResult: skipif = kwargs.get("skipif") if skipif: try: assert_bash_exec(bash, skipif) except AssertionError: pass else: pytest.skip(skipif) return CompletionResult("", []) cwd = kwargs.get("cwd") if cwd: assert_bash_exec(bash, "cd '%s'" % cwd) env_prefix = "_BASHCOMP_TEST_" env = kwargs.get("env", {}) if env: # Back up environment and apply new one assert_bash_exec( bash, " ".join('%s%s="$%s"' % (env_prefix, k, k) for k in env.keys())) assert_bash_exec( bash, "export %s" % " ".join("%s=%s" % (k, v) for k, v in env.items())) bash.send(cmd + "\t") bash.expect_exact(cmd) bash.send(MAGIC_MARK) got = bash.expect([ # 0: multiple lines, result in .before r"\r\n" + re.escape(PS1 + cmd) + ".*" + MAGIC_MARK, # 1: no completion r"^" + MAGIC_MARK, # 2: on same line, result in .match r"^([^\r]+)%s$" % MAGIC_MARK, pexpect.EOF, pexpect.TIMEOUT, ]) if got == 0: output = bash.before if output.endswith(MAGIC_MARK): output = bash.before[:-len(MAGIC_MARK)] result = CompletionResult(output) elif got == 2: output = bash.match.group(1) result = CompletionResult(output, [shlex.split(cmd + output)[-1]]) else: # TODO: warn about EOF/TIMEOUT? result = CompletionResult("", []) bash.sendintr() bash.expect_exact(PS1) if env: # Restore environment, and clean up backup # TODO: Test with declare -p if a var was set, backup only if yes, and # similarly restore only backed up vars. Should remove some need # for ignore_env. assert_bash_exec( bash, "export %s" % " ".join('%s="$%s%s"' % (k, env_prefix, k) for k in env.keys())) assert_bash_exec( bash, "unset -v %s" % " ".join("%s%s" % (env_prefix, k) for k in env.keys())) if cwd: assert_bash_exec(bash, "cd - >/dev/null") return result
def spawnAction(self, sp: spawn): print("expecting {}".format(self)) yield sp.expect(self)
def expect_iterm_current_dir(zsh: pexpect.spawn) -> bytes: """Match a iTerm CurrentDir escape sequence. """ zsh.expect(b"\x1b](?:1337|50);CurrentDir=(?P<iterm_current_dir_path>.*?)\x07") return zsh.match.group("iterm_current_dir_path")
def spawnAction(self, sp: spawn): print("sending {}".format(self)) yield sp.send(self)
def connect(self, connection=None): """ See :meth:`BaseShell.connect` for more information. """ connection = connection or self._default_connection or '0' if connection in self._connections and self.is_connected(connection): raise AlreadyConnectedError(connection) # Create a child process spawn = Spawn( self._get_connect_command().strip(), **self._spawn_args ) self._connections[connection] = spawn try: # If connection is via user if self._user is not None: spawn.expect( [self._user_match], timeout=self._timeout ) spawn.sendline(self._user) # If connection is via password if self._password is not None: spawn.expect( [self._password_match], timeout=self._timeout ) spawn.sendline(self._password) # Setup shell before using it self._setup_shell(connection) # Execute initial command if required if self._initial_command is not None: spawn.expect( self._prompt, timeout=self._timeout ) spawn.sendline(self._initial_command) # Wait for command response to match the prompt spawn.expect( self._prompt, timeout=self._timeout ) except: # Always remove bad connections if it failed del self._connections[connection] raise # Set connection as default connection if required if self.default_connection is None: self.default_connection = connection
def connect(self, connection=None): """ See :meth:`BaseShell.connect` for more information. """ connection = connection or self._default_connection or '0' if connection in self._connections and self.is_connected(connection): raise AlreadyConnectedError(connection) # Create a child process spawn = Spawn(self._get_connect_command().strip(), **self._spawn_args) self._connections[connection] = spawn try: # If connection is via user if self._user is not None: spawn.expect([self._user_match], timeout=self._timeout) spawn.sendline(self._user) # If connection is via password if self._password is not None: spawn.expect([self._password_match], timeout=self._timeout) spawn.sendline(self._password) # Setup shell before using it self._setup_shell(connection) # Execute initial command if required if self._initial_command is not None: spawn.expect(self._prompt, timeout=self._timeout) spawn.sendline(self._initial_command) # Wait for command response to match the prompt spawn.expect(self._prompt, timeout=self._timeout) except: # Always remove bad connections if it failed del self._connections[connection] raise # Set connection as default connection if required if self.default_connection is None: self.default_connection = connection