1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! The main crate of Rexpect
//!
//! # Overview
//!
//! Rexpect is a loose port of [pexpect](pexpect.readthedocs.io/en/stable/)
//! which itself is inspired by Don Libe's expect.
//!
//! It's main components (depending on your need you can use either of those)
//!
//! - [session](session/index.html): automate stuff in Rust
//! - [reader](reader/index.html): a non-blocking reader with buffering, matching on
//!   strings/regex/...
//! - [process](process/index.html): spawn a process in a pty
//!
//! # Basic example
//!
//! ```no_run
//!
//! extern crate rexpect;
//!
//! use rexpect::spawn;
//! use rexpect::errors::*;
//!
//! fn do_ftp() -> Result<()> {
//!     let mut p = spawn("ftp speedtest.tele2.net", Some(2000))?;
//!     p.exp_regex("Name \\(.*\\):")?;
//!     p.send_line("anonymous")?;
//!     p.exp_string("Password")?;
//!     p.send_line("test")?;
//!     p.exp_string("ftp>")?;
//!     p.send_line("cd upload")?;
//!     p.exp_string("successfully changed.\r\nftp>")?;
//!     p.send_line("pwd")?;
//!     p.exp_regex("[0-9]+ \"/upload\"")?;
//!     p.send_line("exit")?;
//!     p.exp_eof()?;
//!     Ok(())
//! }
//!
//!
//! fn main() {
//!     do_ftp().unwrap_or_else(|e| panic!("ftp job failed with {}", e));
//! }
//! ```
//!
//! # Example with bash
//!
//! Tip: try the chain of commands first in a bash session.
//! The tricky thing is to get the wait_for_prompt right.
//! What `wait_for_prompt` actually does is seeking to the next
//! visible prompt. If you forgot to call this once your next call to
//! `wait_for_prompt` comes out of sync and you're seeking to a prompt
//! printed "above" the last `execute()`.
//!
//! ```no_run
//! extern crate rexpect;
//! use rexpect::spawn_bash;
//! use rexpect::errors::*;
//!
//!
//! fn run() -> Result<()> {
//!     let mut p = spawn_bash(Some(30_000))?;
//!     p.execute("ping 8.8.8.8", "bytes of data")?;
//!     p.send_control('z')?;
//!     p.wait_for_prompt()?;
//!     p.execute("bg", "suspended")?;
//!     p.send_line("sleep 1")?;
//!     p.wait_for_prompt()?;
//!     p.execute("fg", "continued")?;
//!     p.send_control('c')?;
//!     p.exp_string("packet loss")?;
//!     Ok(())
//! }
//!
//! fn main() {
//!     run().unwrap_or_else(|e| panic!("bash process failed with {}", e));
//! }
//!
//! ```

pub mod process;
pub mod session;
pub mod reader;

pub use session::{spawn, spawn_bash, spawn_python, spawn_stream};
pub use reader::ReadUntil;

pub mod errors {
    use std::time;
    // Create the Error, ErrorKind, ResultExt, and Result types
    error_chain::error_chain!{
        errors {
            EOF(expected:String, got:String, exit_code:Option<String>) {
                description("End of filestream (usually stdout) occurred, most probably\
                             because the process terminated")
                display("EOF (End of File): Expected {} but got EOF after reading \"{}\", \
                             process terminated with {:?}", expected, got,
                             exit_code.as_ref()
                             .unwrap_or(& "unknown".to_string()))
            }
            BrokenPipe {
                description("The pipe to the process is broken. Most probably because\
                the process died.")
                display("PipeError")
            }
            Timeout(expected:String, got:String, timeout:time::Duration) {
                description("The process didn't end within the given timeout")
                display("Timeout Error: Expected {} but got \"{}\" (after waiting {} ms)",
                        expected, got, (timeout.as_secs() * 1000) as u32
                        + timeout.subsec_nanos() / 1_000_000)
            }
            EmptyProgramName {
                description("The provided program name is empty.")
                display("EmptyProgramName")
            }
        }
    }
}