Skip to content

Commit 2771b71

Browse files
committed
Add Options to configure NBReader
Signed-off-by: phaer <[email protected]>
1 parent 6b37f7e commit 2771b71

File tree

9 files changed

+97
-69
lines changed

9 files changed

+97
-69
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use rexpect::spawn;
3838
use rexpect::error::*;
3939
4040
fn do_ftp() -> Result<(), Error> {
41-
let mut p = spawn("ftp speedtest.tele2.net", Some(30_000), false)?;
41+
let mut p = spawn("ftp speedtest.tele2.net", Some(30_000))?;
4242
p.exp_regex("Name \\(.*\\):")?;
4343
p.send_line("anonymous")?;
4444
p.exp_string("Password")?;
@@ -65,7 +65,7 @@ use rexpect::spawn_bash;
6565
use rexpect::error::*;
6666
6767
fn do_bash() -> Result<(), Error> {
68-
let mut p = spawn_bash(Some(2000), false)?;
68+
let mut p = spawn_bash(Some(2000))?;
6969
7070
// case 1: wait until program is done
7171
p.send_line("hostname")?;
@@ -115,7 +115,7 @@ use rexpect::spawn_bash;
115115
use rexpect::error::*;
116116
117117
fn do_bash_jobcontrol() -> Result<(), Error> {
118-
let mut p = spawn_bash(Some(1000), false)?;
118+
let mut p = spawn_bash(Some(1000))?;
119119
p.execute("ping 8.8.8.8", "bytes of data")?;
120120
p.send_control('z')?;
121121
p.wait_for_prompt()?;

examples/bash.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rexpect::error::Error;
22
use rexpect::spawn_bash;
33

44
fn main() -> Result<(), Error> {
5-
let mut p = spawn_bash(Some(1000), false)?;
5+
let mut p = spawn_bash(Some(1000))?;
66
p.execute("ping 8.8.8.8", "bytes")?;
77
p.send_control('z')?;
88
p.wait_for_prompt()?;

examples/bash_read.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rexpect::error::Error;
22
use rexpect::spawn_bash;
33

44
fn main() -> Result<(), Error> {
5-
let mut p = spawn_bash(Some(2000), false)?;
5+
let mut p = spawn_bash(Some(2000))?;
66

77
// case 1: wait until program is done
88
p.send_line("hostname")?;

examples/exit_code.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ use rexpect::spawn;
77
/// cat exited with code 1
88
/// Output (stdout and stderr): cat: /this/does/not/exist: No such file or directory
99
fn main() -> Result<(), Error> {
10-
let p = spawn("cat /etc/passwd", Some(2000), false)?;
10+
let p = spawn("cat /etc/passwd", Some(2000))?;
1111
match p.process.wait() {
1212
Ok(wait::WaitStatus::Exited(_, 0)) => println!("cat exited with code 0, all good!"),
1313
_ => println!("cat exited with code >0, or it was killed"),
1414
}
1515

16-
let mut p = spawn("cat /this/does/not/exist", Some(2000), false)?;
16+
let mut p = spawn("cat /this/does/not/exist", Some(2000))?;
1717
match p.process.wait() {
1818
Ok(wait::WaitStatus::Exited(_, 0)) => println!("cat succeeded"),
1919
Ok(wait::WaitStatus::Exited(_, c)) => {

examples/ftp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rexpect::error::Error;
22
use rexpect::spawn;
33

44
fn main() -> Result<(), Error> {
5-
let mut p = spawn("ftp speedtest.tele2.net", Some(2000), false)?;
5+
let mut p = spawn("ftp speedtest.tele2.net", Some(2000))?;
66
p.exp_regex("Name \\(.*\\):")?;
77
p.send_line("anonymous")?;
88
p.exp_string("Password")?;

examples/repl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn ed_session() -> Result<PtyReplSession, Error> {
1212

1313
// used for `wait_for_prompt()`
1414
prompt: "> ".to_string(),
15-
pty_session: spawn("/bin/ed -p '> '", Some(2000), false)?,
15+
pty_session: spawn("/bin/ed -p '> '", Some(2000))?,
1616
// command which is sent when the instance of this struct is dropped
1717
// in the below example this is not needed, but if you don't explicitly
1818
// exit a REPL then rexpect tries to send a SIGTERM and depending on the repl

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//! use rexpect::error::Error;
2121
//!
2222
//! fn main() -> Result<(), Error> {
23-
//! let mut p = spawn("ftp speedtest.tele2.net", Some(2000), false)?;
23+
//! let mut p = spawn("ftp speedtest.tele2.net", Some(2000))?;
2424
//! p.exp_regex("Name \\(.*\\):")?;
2525
//! p.send_line("anonymous")?;
2626
//! p.exp_string("Password")?;
@@ -50,7 +50,7 @@
5050
//! use rexpect::error::Error;
5151
//!
5252
//! fn main() -> Result<(), Error> {
53-
//! let mut p = spawn_bash(Some(30_000), false)?;
53+
//! let mut p = spawn_bash(Some(30_000))?;
5454
//! p.execute("ping 8.8.8.8", "bytes of data")?;
5555
//! p.send_control('z')?;
5656
//! p.wait_for_prompt()?;
@@ -70,7 +70,7 @@ pub mod reader;
7070
pub mod session;
7171

7272
pub use reader::ReadUntil;
73-
pub use session::{spawn, spawn_bash, spawn_python, spawn_stream};
73+
pub use session::{spawn, spawn_bash, spawn_python, spawn_stream, spawn_with_options};
7474

7575
// include the README.md here to test its doc
7676
#[doc = include_str!("../README.md")]

src/reader.rs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ pub fn find(needle: &ReadUntil, buffer: &str, eof: bool) -> Option<(usize, usize
9898
}
9999
}
100100

101+
/// Options for NBReader
102+
///
103+
/// - timeout:
104+
/// + `None`: read_until is blocking forever. This is probably not what you want
105+
/// + `Some(millis)`: after millis milliseconds a timeout error is raised
106+
/// - strip_ansi_escape_codes: Whether to filter out escape codes, such as colors.
107+
#[derive(Default)]
108+
pub struct Options {
109+
pub timeout_ms: Option<u64>,
110+
pub strip_ansi_escape_codes: bool,
111+
}
112+
101113
/// Non blocking reader
102114
///
103115
/// Typically you'd need that to check for output of a process without blocking your thread.
@@ -116,15 +128,8 @@ impl NBReader {
116128
/// # Arguments:
117129
///
118130
/// - f: file like object
119-
/// - timeout:
120-
/// + `None`: read_until is blocking forever. This is probably not what you want
121-
/// + `Some(millis)`: after millis milliseconds a timeout error is raised
122-
/// - strip_ansi_escape_codes: Whether to filter out escape codes, such as colors.
123-
pub fn new<R: Read + Send + 'static>(
124-
f: R,
125-
timeout: Option<u64>,
126-
strip_ansi_escape_codes: bool
127-
) -> NBReader {
131+
/// - options: see `Options`
132+
pub fn new<R: Read + Send + 'static>(f: R, options: Options) -> NBReader {
128133
let (tx, rx) = channel();
129134

130135
// spawn a thread which reads one char and sends it to tx
@@ -140,21 +145,20 @@ impl NBReader {
140145
break;
141146
}
142147
Ok(_) => {
143-
if strip_ansi_escape_codes && byte[0] == 27 {
148+
if options.strip_ansi_escape_codes && byte[0] == 27 {
144149
while let Ok(_) = reader.read(&mut byte) {
145150
if char::from(byte[0]).is_alphabetic() {
146151
break;
147152
}
148153
}
149-
}
150-
else {
154+
} else {
151155
tx.send(Ok(PipedChar::Char(byte[0])))
152-
.map_err(|_| Error::MpscSendError)?;
156+
.map_err(|_| Error::MpscSendError)?;
153157
}
154158
}
155159
Err(error) => {
156160
tx.send(Err(PipeError::IO(error)))
157-
.map_err(|_| Error::MpscSendError)?;
161+
.map_err(|_| Error::MpscSendError)?;
158162
}
159163
}
160164
}
@@ -168,7 +172,7 @@ impl NBReader {
168172
reader: rx,
169173
buffer: String::with_capacity(1024),
170174
eof: false,
171-
timeout: timeout.map(time::Duration::from_millis),
175+
timeout: options.timeout_ms.map(time::Duration::from_millis),
172176
}
173177
}
174178

@@ -219,11 +223,11 @@ impl NBReader {
219223
///
220224
/// ```
221225
/// # use std::io::Cursor;
222-
/// use rexpect::reader::{NBReader, ReadUntil, Regex};
226+
/// use rexpect::reader::{NBReader, ReadUntil, Regex, Options};
223227
/// // instead of a Cursor you would put your process output or file here
224228
/// let f = Cursor::new("Hello, miss!\n\
225229
/// What do you mean: 'miss'?");
226-
/// let mut e = NBReader::new(f, None, false);
230+
/// let mut e = NBReader::new(f, Options::default());
227231
///
228232
/// let (first_line, _) = e.read_until(&ReadUntil::String('\n'.to_string())).unwrap();
229233
/// assert_eq!("Hello, miss!", &first_line);
@@ -303,7 +307,7 @@ mod tests {
303307
#[test]
304308
fn test_expect_melon() {
305309
let f = io::Cursor::new("a melon\r\n");
306-
let mut r = NBReader::new(f, None, false);
310+
let mut r = NBReader::new(f, Options::default());
307311
assert_eq!(
308312
("a melon".to_string(), "\r\n".to_string()),
309313
r.read_until(&ReadUntil::String("\r\n".to_string()))
@@ -320,7 +324,7 @@ mod tests {
320324
#[test]
321325
fn test_regex() {
322326
let f = io::Cursor::new("2014-03-15");
323-
let mut r = NBReader::new(f, None, false);
327+
let mut r = NBReader::new(f, Options::default());
324328
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
325329
assert_eq!(
326330
("".to_string(), "2014-03-15".to_string()),
@@ -332,7 +336,7 @@ mod tests {
332336
#[test]
333337
fn test_regex2() {
334338
let f = io::Cursor::new("2014-03-15");
335-
let mut r = NBReader::new(f, None, false);
339+
let mut r = NBReader::new(f, Options::default());
336340
let re = Regex::new(r"-\d{2}-").unwrap();
337341
assert_eq!(
338342
("2014".to_string(), "-03-".to_string()),
@@ -344,7 +348,7 @@ mod tests {
344348
#[test]
345349
fn test_nbytes() {
346350
let f = io::Cursor::new("abcdef");
347-
let mut r = NBReader::new(f, None, false);
351+
let mut r = NBReader::new(f, Options::default());
348352
assert_eq!(
349353
("".to_string(), "ab".to_string()),
350354
r.read_until(&ReadUntil::NBytes(2)).expect("2 bytes")
@@ -362,7 +366,7 @@ mod tests {
362366
#[test]
363367
fn test_any_with_multiple_possible_matches() {
364368
let f = io::Cursor::new("zero one two three four five");
365-
let mut r = NBReader::new(f, None, false);
369+
let mut r = NBReader::new(f, Options::default());
366370

367371
let result = r
368372
.read_until(&ReadUntil::Any(vec![
@@ -377,7 +381,7 @@ mod tests {
377381
#[test]
378382
fn test_any_with_same_start_different_length() {
379383
let f = io::Cursor::new("hi hello");
380-
let mut r = NBReader::new(f, None, false);
384+
let mut r = NBReader::new(f, Options::default());
381385

382386
let result = r
383387
.read_until(&ReadUntil::Any(vec![
@@ -392,7 +396,7 @@ mod tests {
392396
#[test]
393397
fn test_eof() {
394398
let f = io::Cursor::new("lorem ipsum dolor sit amet");
395-
let mut r = NBReader::new(f, None, false);
399+
let mut r = NBReader::new(f, Options::default());
396400
r.read_until(&ReadUntil::NBytes(2)).expect("2 bytes");
397401
assert_eq!(
398402
("".to_string(), "rem ipsum dolor sit amet".to_string()),
@@ -403,18 +407,24 @@ mod tests {
403407
#[test]
404408
fn test_skip_ansi_codes() {
405409
let f = io::Cursor::new("\x1b[31;1;4mHello\x1b[0m");
406-
let mut r = NBReader::new(f, None, true);
407-
let bytes = r.read_until(&ReadUntil::String("Hello".to_string())).unwrap();
410+
let mut r = NBReader::new(
411+
f,
412+
Options {
413+
timeout_ms: None,
414+
strip_ansi_escape_codes: true,
415+
},
416+
);
417+
let bytes = r
418+
.read_until(&ReadUntil::String("Hello".to_string()))
419+
.unwrap();
408420
assert_eq!(bytes, ("".to_string(), "Hello".to_string()));
409421
assert_eq!(None, r.try_read());
410-
411422
}
412423

413-
414424
#[test]
415425
fn test_try_read() {
416426
let f = io::Cursor::new("lorem");
417-
let mut r = NBReader::new(f, None, false);
427+
let mut r = NBReader::new(f, Options::default());
418428
let bytes = r.read_until(&ReadUntil::NBytes(4)).unwrap();
419429
assert!(bytes.0.is_empty());
420430
assert_eq!(bytes.1, "lore");

0 commit comments

Comments
 (0)