Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions examples/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,15 @@ use rexpect::session::PtyReplSession;
use rexpect::spawn;

fn ed_session() -> Result<PtyReplSession, Error> {
let mut ed = PtyReplSession {
let mut ed = PtyReplSession::new(spawn("/bin/ed -p '> '", Some(2000))?, "> ".to_owned())
// for `echo_on` you need to figure that out by trial and error.
// For bash and python repl it is false
echo_on: false,

// used for `wait_for_prompt()`
prompt: "> ".to_owned(),
pty_session: spawn("/bin/ed -p '> '", Some(2000))?,
.echo_on(false)
// command which is sent when the instance of this struct is dropped
// in the below example this is not needed, but if you don't explicitly
// exit a REPL then rexpect tries to send a SIGTERM and depending on the repl
// this does not end the repl and would end up in an error
quit_command: Some("Q".to_owned()),
};
.quit_command(Some("Q".to_owned()));
ed.wait_for_prompt()?;
Ok(ed)
}
Expand Down
1 change: 1 addition & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::time;

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("EOF (End of File): Expected {:?} but got EOF after reading {:?} process terminated with {:?}", .expected, .got, .exit_code.as_ref().unwrap_or(&"unknown".to_owned()))]
EOF {
Expand Down
6 changes: 3 additions & 3 deletions src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use nix;
use nix::fcntl::{OFlag, open};
use nix::libc::STDERR_FILENO;
use nix::pty::{PtyMaster, grantpt, posix_openpt, unlockpt};
use nix::sys::{signal, wait};
use nix::sys::{stat, termios};
use nix::unistd::{
ForkResult, Pid, close, dup, dup2_stderr, dup2_stdin, dup2_stdout, fork, setsid,
Expand All @@ -17,7 +18,6 @@ use std::os::unix::process::CommandExt;
use std::process::Command;
use std::{thread, time};

pub use nix::sys::{signal, wait};
pub use signal::Signal;
pub use wait::WaitStatus;

Expand Down Expand Up @@ -57,8 +57,8 @@ pub use wait::WaitStatus;
/// # }
/// ```
pub struct PtyProcess {
pub pty: PtyMaster,
pub child_pid: Pid,
pty: PtyMaster,
pub(crate) child_pid: Pid,
kill_timeout: Option<time::Duration>,
}

Expand Down
7 changes: 4 additions & 3 deletions src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ pub struct Options {
/// `None`: `read_until` is blocking forever. This is probably not what you want
///
/// `Some(millis)`: after millis milliseconds a timeout error is raised
pub timeout_ms: Option<u64>,
pub(crate) timeout_ms: Option<u64>,
/// Whether to filter out escape codes, such as colors.
pub strip_ansi_escape_codes: bool,
pub(crate) strip_ansi_escape_codes: bool,
}

impl Options {
Expand Down Expand Up @@ -214,6 +214,7 @@ impl NBReader {
/// See [`NBReader::read_until`]
///
/// Note that when used with a tty the lines end with \r\n
#[non_exhaustive]
pub enum ReadUntil {
/// Searches for string (use '\n'.`to_string()` to search for newline).
///
Expand Down Expand Up @@ -268,7 +269,7 @@ impl fmt::Display for ReadUntil {
/// Tuple with match positions:
/// 1. position before match (0 in case of EOF and Nbytes)
/// 2. position after match
pub fn find(needle: &ReadUntil, buffer: &str, eof: bool) -> Option<(usize, usize)> {
fn find(needle: &ReadUntil, buffer: &str, eof: bool) -> Option<(usize, usize)> {
match needle {
ReadUntil::String(s) => buffer.find(s).map(|pos| (pos, pos + s.len())),
ReadUntil::Regex(pattern) => pattern.find(buffer).map(|mat| (mat.start(), mat.end())),
Expand Down
24 changes: 11 additions & 13 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use std::process::Command;
use tempfile;

pub struct StreamSession<W: Write> {
pub writer: LineWriter<W>,
pub reader: NBReader,
writer: LineWriter<W>,
reader: NBReader,
}

impl<W: Write> StreamSession<W> {
Expand Down Expand Up @@ -166,8 +166,8 @@ impl<W: Write> StreamSession<W> {
/// Interact with a process with read/write/signals, etc.
#[allow(dead_code)]
pub struct PtySession {
pub process: PtyProcess,
pub stream: StreamSession<File>,
process: PtyProcess,
stream: StreamSession<File>,
}

// make StreamSession's methods available directly
Expand Down Expand Up @@ -273,10 +273,10 @@ pub fn spawn_with_options(command: Command, options: Options) -> Result<PtySessi
/// You have a prompt where a user inputs commands and the shell
/// executes it and writes some output
pub struct PtyReplSession {
pub pty_session: PtySession,
pub prompt: String,
pub quit_command: Option<String>,
pub echo_on: bool,
pty_session: PtySession,
prompt: String,
quit_command: Option<String>,
echo_on: bool,
}

impl PtyReplSession {
Expand Down Expand Up @@ -484,17 +484,15 @@ pub fn spawn_stream<R: Read + Send + 'static, W: Write>(
#[cfg(test)]
mod tests {
use super::*;
use nix::sys::wait;

#[test]
fn test_read_line() -> Result<(), Error> {
let mut s = spawn("cat", Some(100000))?;
s.send_line("hans")?;
assert_eq!("hans", s.read_line()?);
let should = crate::process::wait::WaitStatus::Signaled(
s.process.child_pid,
crate::process::signal::Signal::SIGTERM,
false,
);
let should =
wait::WaitStatus::Signaled(s.process.child_pid, crate::process::Signal::SIGTERM, false);
assert_eq!(should, s.process.exit()?);
Ok(())
}
Expand Down
Loading