Struct expectrl::repl::ReplSession

source ·
pub struct ReplSession<P = OsProcess, S = OsProcessStream> { /* private fields */ }
Expand description

A repl session: e.g. bash or the python shell: you have a prompt where a user inputs commands and the shell which executes them and manages IO streams.

Implementations§

source§

impl<P, S> ReplSession<P, S>

source

pub fn new( session: Session<P, S>, prompt: String, quit_command: Option<String>, is_echo: bool ) -> Self

Spawn function creates a repl session.

The argument list is: - session; a spawned session which repl will wrap. - prompt; a string which will identify that the command was run. - quit_command; a command which will be called when ReplSession instance is dropped. - is_echo_on; determines whether the prompt check will be done twice.

Examples found in repository?
examples/shell.rs (line 9)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() -> Result<()> {
    let mut p = expectrl::spawn("sh")?;
    p.get_process_mut().set_echo(true, None)?;

    let mut shell = ReplSession::new(p, String::from("sh-5.1$"), Some(String::from("exit")), true);

    shell.expect_prompt()?;

    let output = exec(&mut shell, "echo Hello World")?;
    println!("{:?}", output);

    let output = exec(&mut shell, "echo '2 + 3' | bc")?;
    println!("{:?}", output);

    Ok(())
}
source

pub fn get_prompt(&self) -> &str

Get a used prompt.

source

pub fn get_quit_command(&self) -> Option<&str>

Get a used quit command.

source

pub fn is_echo(&self) -> bool

Get a echo settings.

source

pub fn into_session(self) -> Session<P, S>

Get an inner session.

source§

impl<P, S: Read + NonBlocking> ReplSession<P, S>

source

pub fn expect_prompt(&mut self) -> Result<(), Error>

Block until prompt is found

Examples found in repository?
examples/shell.rs (line 11)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() -> Result<()> {
    let mut p = expectrl::spawn("sh")?;
    p.get_process_mut().set_echo(true, None)?;

    let mut shell = ReplSession::new(p, String::from("sh-5.1$"), Some(String::from("exit")), true);

    shell.expect_prompt()?;

    let output = exec(&mut shell, "echo Hello World")?;
    println!("{:?}", output);

    let output = exec(&mut shell, "echo '2 + 3' | bc")?;
    println!("{:?}", output);

    Ok(())
}
More examples
Hide additional examples
examples/ping.rs (line 11)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fn main() -> Result<(), Error> {
    let mut p = spawn_bash()?;
    p.send_line("ping 8.8.8.8")?;
    p.expect("bytes of data")?;
    p.send(ControlCode::try_from("^Z").unwrap())?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into background
    p.send_line("bg")?;
    p.expect("ping 8.8.8.8")?;
    p.expect_prompt()?;
    p.send_line("sleep 0.5")?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into foreground
    p.send_line("fg")?;
    p.expect("ping 8.8.8.8")?;
    p.send(ControlCode::try_from("^D").unwrap())?;
    p.expect("packet loss")?;

    Ok(())
}
examples/bash.rs (line 21)
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
fn main() {
    let mut p = spawn_bash().unwrap();

    // case 1: execute
    let hostname = p.execute("hostname").unwrap();
    println!("Current hostname: {:?}", String::from_utf8_lossy(&hostname));

    // case 2: wait until done, only extract a few infos
    p.send_line("wc /etc/passwd").unwrap();
    // `exp_regex` returns both string-before-match and match itself, discard first
    let lines = p.expect(Regex("[0-9]+")).unwrap();
    let words = p.expect(Regex("[0-9]+")).unwrap();
    let bytes = p.expect(Regex("[0-9]+")).unwrap();
    p.expect_prompt().unwrap(); // go sure `wc` is really done
    println!(
        "/etc/passwd has {} lines, {} words, {} chars",
        String::from_utf8_lossy(&lines[0]),
        String::from_utf8_lossy(&words[0]),
        String::from_utf8_lossy(&bytes[0]),
    );

    // case 3: read while program is still executing
    p.send_line("ping 8.8.8.8").unwrap(); // returns when it sees "bytes of data" in output
    for _ in 0..5 {
        // times out if one ping takes longer than 2s
        let duration = p.expect(Regex("[0-9. ]+ ms")).unwrap();
        println!("Roundtrip time: {}", String::from_utf8_lossy(&duration[0]));
    }

    p.send(ControlCode::EOT).unwrap();
}
source§

impl<P, S: Read + NonBlocking + Write> ReplSession<P, S>

source

pub fn execute<SS: AsRef<str> + Clone>( &mut self, cmd: SS ) -> Result<Vec<u8>, Error>

Send a command to a repl and verifies that it exited. Returning it’s output.

Examples found in repository?
examples/shell.rs (line 24)
23
24
25
26
27
28
29
30
fn exec(shell: &mut ReplSession, cmd: &str) -> Result<String> {
    let buf = shell.execute(cmd)?;
    let mut string = String::from_utf8_lossy(&buf).into_owned();
    string = string.replace("\r\n\u{1b}[?2004l\r", "");
    string = string.replace("\r\n\u{1b}[?2004h", "");

    Ok(string)
}
More examples
Hide additional examples
examples/python.rs (line 7)
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
    let mut p = spawn_python().unwrap();

    p.execute("import platform").unwrap();
    p.send_line("platform.node()").unwrap();

    let found = p.expect(Regex(r"'.*'")).unwrap();

    println!(
        "Platform {}",
        String::from_utf8_lossy(found.get(0).unwrap())
    );
}
examples/bash.rs (line 12)
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
fn main() {
    let mut p = spawn_bash().unwrap();

    // case 1: execute
    let hostname = p.execute("hostname").unwrap();
    println!("Current hostname: {:?}", String::from_utf8_lossy(&hostname));

    // case 2: wait until done, only extract a few infos
    p.send_line("wc /etc/passwd").unwrap();
    // `exp_regex` returns both string-before-match and match itself, discard first
    let lines = p.expect(Regex("[0-9]+")).unwrap();
    let words = p.expect(Regex("[0-9]+")).unwrap();
    let bytes = p.expect(Regex("[0-9]+")).unwrap();
    p.expect_prompt().unwrap(); // go sure `wc` is really done
    println!(
        "/etc/passwd has {} lines, {} words, {} chars",
        String::from_utf8_lossy(&lines[0]),
        String::from_utf8_lossy(&words[0]),
        String::from_utf8_lossy(&bytes[0]),
    );

    // case 3: read while program is still executing
    p.send_line("ping 8.8.8.8").unwrap(); // returns when it sees "bytes of data" in output
    for _ in 0..5 {
        // times out if one ping takes longer than 2s
        let duration = p.expect(Regex("[0-9. ]+ ms")).unwrap();
        println!("Roundtrip time: {}", String::from_utf8_lossy(&duration[0]));
    }

    p.send(ControlCode::EOT).unwrap();
}
source

pub fn send_line<Text: AsRef<str>>(&mut self, line: Text) -> Result<(), Error>

Sends line to repl (and flush the output).

If echo_on=true wait for the input to appear.

Examples found in repository?
examples/python.rs (line 8)
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
    let mut p = spawn_python().unwrap();

    p.execute("import platform").unwrap();
    p.send_line("platform.node()").unwrap();

    let found = p.expect(Regex(r"'.*'")).unwrap();

    println!(
        "Platform {}",
        String::from_utf8_lossy(found.get(0).unwrap())
    );
}
More examples
Hide additional examples
examples/ping.rs (line 8)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fn main() -> Result<(), Error> {
    let mut p = spawn_bash()?;
    p.send_line("ping 8.8.8.8")?;
    p.expect("bytes of data")?;
    p.send(ControlCode::try_from("^Z").unwrap())?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into background
    p.send_line("bg")?;
    p.expect("ping 8.8.8.8")?;
    p.expect_prompt()?;
    p.send_line("sleep 0.5")?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into foreground
    p.send_line("fg")?;
    p.expect("ping 8.8.8.8")?;
    p.send(ControlCode::try_from("^D").unwrap())?;
    p.expect("packet loss")?;

    Ok(())
}
examples/bash.rs (line 16)
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
fn main() {
    let mut p = spawn_bash().unwrap();

    // case 1: execute
    let hostname = p.execute("hostname").unwrap();
    println!("Current hostname: {:?}", String::from_utf8_lossy(&hostname));

    // case 2: wait until done, only extract a few infos
    p.send_line("wc /etc/passwd").unwrap();
    // `exp_regex` returns both string-before-match and match itself, discard first
    let lines = p.expect(Regex("[0-9]+")).unwrap();
    let words = p.expect(Regex("[0-9]+")).unwrap();
    let bytes = p.expect(Regex("[0-9]+")).unwrap();
    p.expect_prompt().unwrap(); // go sure `wc` is really done
    println!(
        "/etc/passwd has {} lines, {} words, {} chars",
        String::from_utf8_lossy(&lines[0]),
        String::from_utf8_lossy(&words[0]),
        String::from_utf8_lossy(&bytes[0]),
    );

    // case 3: read while program is still executing
    p.send_line("ping 8.8.8.8").unwrap(); // returns when it sees "bytes of data" in output
    for _ in 0..5 {
        // times out if one ping takes longer than 2s
        let duration = p.expect(Regex("[0-9. ]+ ms")).unwrap();
        println!("Roundtrip time: {}", String::from_utf8_lossy(&duration[0]));
    }

    p.send(ControlCode::EOT).unwrap();
}
source

pub fn exit(&mut self) -> Result<(), Error>

Send a quit command.

In async version we it won’t be send on Drop so, If you wan’t it to be send you must do it yourself.

Methods from Deref<Target = Session<P, S>>§

source

pub fn set_expect_timeout(&mut self, expect_timeout: Option<Duration>)

Set the pty session’s expect timeout.

source

pub fn set_expect_lazy(&mut self, lazy: bool)

Set a expect algorithm to be either gready or lazy.

Default algorithm is gready.

See Session::expect.

source

pub fn get_stream(&self) -> &S

Get a reference to original stream.

source

pub fn get_stream_mut(&mut self) -> &mut S

Get a mut reference to original stream.

source

pub fn get_process(&self) -> &P

Get a reference to a process running program.

source

pub fn get_process_mut(&mut self) -> &mut P

Get a mut reference to a process running program.

Examples found in repository?
examples/shell.rs (line 7)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() -> Result<()> {
    let mut p = expectrl::spawn("sh")?;
    p.get_process_mut().set_echo(true, None)?;

    let mut shell = ReplSession::new(p, String::from("sh-5.1$"), Some(String::from("exit")), true);

    shell.expect_prompt()?;

    let output = exec(&mut shell, "echo Hello World")?;
    println!("{:?}", output);

    let output = exec(&mut shell, "echo '2 + 3' | bc")?;
    println!("{:?}", output);

    Ok(())
}
source

pub fn is_alive(&mut self) -> Result<bool, Error>

Verifies whether process is still alive.

source

pub fn expect<N>(&mut self, needle: N) -> Result<Captures, Error>where N: Needle,

Expect waits until a pattern is matched.

If the method returns Ok it is guaranteed that at least 1 match was found.

The match algorthm can be either - gready - lazy

You can set one via Session::set_expect_lazy. Default version is gready.

The implications are. Imagine you use crate::Regex "\d+" to find a match. And your process outputs 123. In case of lazy approach we will match 1. Where’s in case of gready one we will match 123.

Example
let mut p = expectrl::spawn("echo 123").unwrap();
let m = p.expect(expectrl::Regex("\\d+")).unwrap();
assert_eq!(m.get(0).unwrap(), b"123");
let mut p = expectrl::spawn("echo 123").unwrap();
p.set_expect_lazy(true);
let m = p.expect(expectrl::Regex("\\d+")).unwrap();
assert_eq!(m.get(0).unwrap(), b"1");

This behaviour is different from Session::check.

It returns an error if timeout is reached. You can specify a timeout value by Session::set_expect_timeout method.

Examples found in repository?
examples/python.rs (line 10)
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
    let mut p = spawn_python().unwrap();

    p.execute("import platform").unwrap();
    p.send_line("platform.node()").unwrap();

    let found = p.expect(Regex(r"'.*'")).unwrap();

    println!(
        "Platform {}",
        String::from_utf8_lossy(found.get(0).unwrap())
    );
}
More examples
Hide additional examples
examples/log.rs (line 10)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() -> Result<(), Error> {
    let p = spawn("cat")?;
    let mut p = expectrl::session::log(p, std::io::stdout())?;

    #[cfg(not(feature = "async"))]
    {
        p.send_line("Hello World")?;
        p.expect("Hello World")?;
    }
    #[cfg(feature = "async")]
    {
        futures_lite::future::block_on(async {
            p.send_line("Hello World").await?;
            p.expect("Hello World").await
        })?;
    }

    Ok(())
}
examples/ftp.rs (line 6)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() -> Result<(), Error> {
    let mut p = spawn("ftp bks4-speedtest-1.tele2.net")?;
    p.expect(Regex("Name \\(.*\\):"))?;
    p.send_line("anonymous")?;
    p.expect("Password")?;
    p.send_line("test")?;
    p.expect("ftp>")?;
    p.send_line("cd upload")?;
    p.expect("successfully changed.")?;
    p.send_line("pwd")?;
    p.expect(Regex("[0-9]+ \"/upload\""))?;
    p.send(ControlCode::EndOfTransmission)?;
    p.expect("Goodbye.")?;
    Ok(())
}
examples/expect_line.rs (lines 9-13)
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
fn main() {
    let mut session = expectrl::spawn("ls -al").expect("Can't spawn a session");

    loop {
        let m = session
            .expect(Any::boxed(vec![
                Box::new("\r"),
                Box::new("\n"),
                Box::new(Eof),
            ]))
            .expect("Expect failed");

        println!("{:?}", String::from_utf8_lossy(m.as_bytes()));

        let is_eof = m[0].is_empty();
        if is_eof {
            break;
        }

        if m[0] == [b'\n'] {
            continue;
        }

        println!("{:?}", String::from_utf8_lossy(&m[0]));
    }
}
examples/ping.rs (line 9)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fn main() -> Result<(), Error> {
    let mut p = spawn_bash()?;
    p.send_line("ping 8.8.8.8")?;
    p.expect("bytes of data")?;
    p.send(ControlCode::try_from("^Z").unwrap())?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into background
    p.send_line("bg")?;
    p.expect("ping 8.8.8.8")?;
    p.expect_prompt()?;
    p.send_line("sleep 0.5")?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into foreground
    p.send_line("fg")?;
    p.expect("ping 8.8.8.8")?;
    p.send(ControlCode::try_from("^D").unwrap())?;
    p.expect("packet loss")?;

    Ok(())
}
examples/ftp_interact.rs (line 37)
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
fn main() -> Result<(), Error> {
    let mut auth = false;
    let mut login_lookup = Lookup::new();
    let opts = InteractOptions::new(&mut auth).on_output(|ctx| {
        if login_lookup
            .on(ctx.buf, ctx.eof, "Login successful")?
            .is_some()
        {
            **ctx.state = true;
            return Ok(true);
        }

        Ok(false)
    });

    let mut p = spawn("ftp bks4-speedtest-1.tele2.net")?;

    let mut stdin = Stdin::open()?;
    p.interact(&mut stdin, stdout()).spawn(opts)?;
    stdin.close()?;

    if !auth {
        println!("An authefication was not passed");
        return Ok(());
    }

    p.expect("ftp>")?;
    p.send_line("cd upload")?;
    p.expect("successfully changed.")?;
    p.send_line("pwd")?;
    p.expect(Regex("[0-9]+ \"/upload\""))?;
    p.send(ControlCode::EndOfTransmission)?;
    p.expect("Goodbye.")?;
    Ok(())
}
source

pub fn check<N>(&mut self, needle: N) -> Result<Captures, Error>where N: Needle,

Check verifies if a pattern is matched. Returns empty found structure if nothing found.

Is a non blocking version of Session::expect. But its strategy of matching is different from it. It makes search against all bytes available.

Example
use expectrl::{spawn, Regex};
use std::time::Duration;

let mut p = spawn("echo 123").unwrap();
let m = p.check(Regex("\\d+")).unwrap();
assert_eq!(m.get(0).unwrap(), b"123");
source

pub fn is_matched<N>(&mut self, needle: N) -> Result<bool, Error>where N: Needle,

The functions checks if a pattern is matched. It doesn’t consumes bytes from stream.

Its strategy of matching is different from the one in Session::expect. It makes search agains all bytes available.

If you want to get a matched result Session::check and Session::expect is a better option. Because it is not guaranteed that Session::check or Session::expect with the same parameters: - will successed even right after Session::is_matched call. - will operate on the same bytes.

IMPORTANT:

If you call this method with crate::Eof pattern be aware that eof indication MAY be lost on the next interactions. It depends from a process you spawn. So it might be better to use Session::check or Session::expect with Eof.

Example
use expectrl::{spawn, Regex};
use std::time::Duration;

let mut p = spawn("cat").unwrap();
p.send_line("123");
let m = p.is_matched(Regex("\\d+")).unwrap();
assert_eq!(m, true);
source

pub fn send<B: AsRef<[u8]>>(&mut self, buf: B) -> Result<()>

Send text to child’s STDIN.

You can also use methods from std::io::Write instead.

Example
use expectrl::{spawn, ControlCode};

let mut proc = spawn("cat").unwrap();

proc.send("Hello");
proc.send(b"World");
proc.send(ControlCode::try_from("^C").unwrap());
Examples found in repository?
examples/ftp.rs (line 15)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() -> Result<(), Error> {
    let mut p = spawn("ftp bks4-speedtest-1.tele2.net")?;
    p.expect(Regex("Name \\(.*\\):"))?;
    p.send_line("anonymous")?;
    p.expect("Password")?;
    p.send_line("test")?;
    p.expect("ftp>")?;
    p.send_line("cd upload")?;
    p.expect("successfully changed.")?;
    p.send_line("pwd")?;
    p.expect(Regex("[0-9]+ \"/upload\""))?;
    p.send(ControlCode::EndOfTransmission)?;
    p.expect("Goodbye.")?;
    Ok(())
}
More examples
Hide additional examples
examples/ping.rs (line 10)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fn main() -> Result<(), Error> {
    let mut p = spawn_bash()?;
    p.send_line("ping 8.8.8.8")?;
    p.expect("bytes of data")?;
    p.send(ControlCode::try_from("^Z").unwrap())?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into background
    p.send_line("bg")?;
    p.expect("ping 8.8.8.8")?;
    p.expect_prompt()?;
    p.send_line("sleep 0.5")?;
    p.expect_prompt()?;
    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into foreground
    p.send_line("fg")?;
    p.expect("ping 8.8.8.8")?;
    p.send(ControlCode::try_from("^D").unwrap())?;
    p.expect("packet loss")?;

    Ok(())
}
examples/ftp_interact.rs (line 42)
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
fn main() -> Result<(), Error> {
    let mut auth = false;
    let mut login_lookup = Lookup::new();
    let opts = InteractOptions::new(&mut auth).on_output(|ctx| {
        if login_lookup
            .on(ctx.buf, ctx.eof, "Login successful")?
            .is_some()
        {
            **ctx.state = true;
            return Ok(true);
        }

        Ok(false)
    });

    let mut p = spawn("ftp bks4-speedtest-1.tele2.net")?;

    let mut stdin = Stdin::open()?;
    p.interact(&mut stdin, stdout()).spawn(opts)?;
    stdin.close()?;

    if !auth {
        println!("An authefication was not passed");
        return Ok(());
    }

    p.expect("ftp>")?;
    p.send_line("cd upload")?;
    p.expect("successfully changed.")?;
    p.send_line("pwd")?;
    p.expect(Regex("[0-9]+ \"/upload\""))?;
    p.send(ControlCode::EndOfTransmission)?;
    p.expect("Goodbye.")?;
    Ok(())
}
examples/bash.rs (line 37)
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
fn main() {
    let mut p = spawn_bash().unwrap();

    // case 1: execute
    let hostname = p.execute("hostname").unwrap();
    println!("Current hostname: {:?}", String::from_utf8_lossy(&hostname));

    // case 2: wait until done, only extract a few infos
    p.send_line("wc /etc/passwd").unwrap();
    // `exp_regex` returns both string-before-match and match itself, discard first
    let lines = p.expect(Regex("[0-9]+")).unwrap();
    let words = p.expect(Regex("[0-9]+")).unwrap();
    let bytes = p.expect(Regex("[0-9]+")).unwrap();
    p.expect_prompt().unwrap(); // go sure `wc` is really done
    println!(
        "/etc/passwd has {} lines, {} words, {} chars",
        String::from_utf8_lossy(&lines[0]),
        String::from_utf8_lossy(&words[0]),
        String::from_utf8_lossy(&bytes[0]),
    );

    // case 3: read while program is still executing
    p.send_line("ping 8.8.8.8").unwrap(); // returns when it sees "bytes of data" in output
    for _ in 0..5 {
        // times out if one ping takes longer than 2s
        let duration = p.expect(Regex("[0-9. ]+ ms")).unwrap();
        println!("Roundtrip time: {}", String::from_utf8_lossy(&duration[0]));
    }

    p.send(ControlCode::EOT).unwrap();
}
source

pub fn send_line<B: AsRef<[u8]>>(&mut self, buf: B) -> Result<()>

Send a line to child’s STDIN.

Example
use expectrl::{spawn, ControlCode};

let mut proc = spawn("cat").unwrap();

proc.send_line("Hello");
proc.send_line(b"World");
proc.send_line(ControlCode::try_from("^C").unwrap());
Examples found in repository?
examples/log.rs (line 9)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() -> Result<(), Error> {
    let p = spawn("cat")?;
    let mut p = expectrl::session::log(p, std::io::stdout())?;

    #[cfg(not(feature = "async"))]
    {
        p.send_line("Hello World")?;
        p.expect("Hello World")?;
    }
    #[cfg(feature = "async")]
    {
        futures_lite::future::block_on(async {
            p.send_line("Hello World").await?;
            p.expect("Hello World").await
        })?;
    }

    Ok(())
}
More examples
Hide additional examples
examples/ftp.rs (line 7)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() -> Result<(), Error> {
    let mut p = spawn("ftp bks4-speedtest-1.tele2.net")?;
    p.expect(Regex("Name \\(.*\\):"))?;
    p.send_line("anonymous")?;
    p.expect("Password")?;
    p.send_line("test")?;
    p.expect("ftp>")?;
    p.send_line("cd upload")?;
    p.expect("successfully changed.")?;
    p.send_line("pwd")?;
    p.expect(Regex("[0-9]+ \"/upload\""))?;
    p.send(ControlCode::EndOfTransmission)?;
    p.expect("Goodbye.")?;
    Ok(())
}
examples/check.rs (line 12)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn main() {
    let mut session = spawn("python ./tests/source/ansi.py").expect("Can't spawn a session");

    loop {
        match check!(
            &mut session,
            _ = "Password: " => {
                println!("Set password to SECURE_PASSWORD");
                session.send_line("SECURE_PASSWORD").unwrap();
            },
            _ = "Continue [y/n]:" => {
                println!("Stop processing");
                session.send_line("n").unwrap();
            },
        ) {
            Err(Error::Eof) => break,
            result => result.unwrap(),
        };
    }
}
examples/ftp_interact.rs (line 38)
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
fn main() -> Result<(), Error> {
    let mut auth = false;
    let mut login_lookup = Lookup::new();
    let opts = InteractOptions::new(&mut auth).on_output(|ctx| {
        if login_lookup
            .on(ctx.buf, ctx.eof, "Login successful")?
            .is_some()
        {
            **ctx.state = true;
            return Ok(true);
        }

        Ok(false)
    });

    let mut p = spawn("ftp bks4-speedtest-1.tele2.net")?;

    let mut stdin = Stdin::open()?;
    p.interact(&mut stdin, stdout()).spawn(opts)?;
    stdin.close()?;

    if !auth {
        println!("An authefication was not passed");
        return Ok(());
    }

    p.expect("ftp>")?;
    p.send_line("cd upload")?;
    p.expect("successfully changed.")?;
    p.send_line("pwd")?;
    p.expect(Regex("[0-9]+ \"/upload\""))?;
    p.send(ControlCode::EndOfTransmission)?;
    p.expect("Goodbye.")?;
    Ok(())
}
source

pub fn try_read(&mut self, buf: &mut [u8]) -> Result<usize>

Try to read in a non-blocking mode.

Returns [std::io::ErrorKind::WouldBlock] in case if there’s nothing to read.

source

pub fn is_empty(&mut self) -> Result<bool>

Verifyes if stream is empty or not.

source

pub fn interact<I, O>( &mut self, input: I, output: O ) -> InteractSession<&mut Self, I, O>

Interact gives control of the child process to the interactive user (the human at the keyboard or a Reader implementator).

You can set different callbacks to the session, see InteractSession.

Keystrokes are sent to the child process, and the stdout and stderr output of the child process is printed.

When the user types the escape_character this method will return control to a running process. The escape_character will not be transmitted. The default for escape_character is entered as Ctrl-], the very same as BSD telnet.

This simply echos the child stdout and stderr to the real stdout and it echos the real stdin to the child stdin.

BEWARE that interact finishes after a process stops. So after the return you may not obtain a correct status of a process.

In not async mode the default version uses a buzy loop.

  • On linux you can use a polling version using the corresponding feature.
  • On windows the feature is also present but it spawns a thread for pooling which creates a set of obsticales. Specifically if you’re planning to call interact() multiple times it may not be safe. Because the previous threads may still be running.

It works via polling in async mode on both unix and windows.

Example
use std::io::{stdout, Cursor};
use expectrl::{self, interact::InteractOptions};

let mut p = expectrl::spawn("cat").unwrap();

let input = Cursor::new(String::from("Some text right here"));

p.interact(input, stdout()).spawn(InteractOptions::default()).unwrap();
Examples found in repository?
examples/interact.rs (line 22)
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
fn main() {
    let mut sh = spawn(SHELL).expect("Error while spawning sh");

    println!("Now you're in interacting mode");
    println!("To return control back to main type CTRL-] combination");

    let mut stdin = Stdin::open().expect("Failed to create stdin");

    sh.interact(&mut stdin, stdout())
        .spawn(&mut InteractOptions::default())
        .expect("Failed to start interact");

    stdin.close().expect("Failed to close a stdin");

    println!("Exiting");
}
More examples
Hide additional examples
examples/ftp_interact.rs (line 29)
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
fn main() -> Result<(), Error> {
    let mut auth = false;
    let mut login_lookup = Lookup::new();
    let opts = InteractOptions::new(&mut auth).on_output(|ctx| {
        if login_lookup
            .on(ctx.buf, ctx.eof, "Login successful")?
            .is_some()
        {
            **ctx.state = true;
            return Ok(true);
        }

        Ok(false)
    });

    let mut p = spawn("ftp bks4-speedtest-1.tele2.net")?;

    let mut stdin = Stdin::open()?;
    p.interact(&mut stdin, stdout()).spawn(opts)?;
    stdin.close()?;

    if !auth {
        println!("An authefication was not passed");
        return Ok(());
    }

    p.expect("ftp>")?;
    p.send_line("cd upload")?;
    p.expect("successfully changed.")?;
    p.send_line("pwd")?;
    p.expect(Regex("[0-9]+ \"/upload\""))?;
    p.send(ControlCode::EndOfTransmission)?;
    p.expect("Goodbye.")?;
    Ok(())
}
examples/interact_with_callback.rs (line 60)
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
fn main() {
    let mut output_action = Lookup::new();
    let mut input_action = Lookup::new();
    let mut state = State::default();
    let opts = InteractOptions::new(&mut state)
        .on_output(|mut ctx| {
            let m = output_action.on(ctx.buf, ctx.eof, "Continue [y/n]:")?;
            if m.is_some() {
                ctx.state.wait_for_continue = Some(true);
            };

            let m = output_action.on(ctx.buf, ctx.eof, Regex("status:\\s*.*\\w+.*\\r\\n"))?;
            if m.is_some() {
                ctx.state.stutus_verification_counter =
                    Some(ctx.state.stutus_verification_counter.map_or(1, |c| c + 1));
                output_action.clear();
            }

            Ok(false)
        })
        .on_input(|mut ctx| {
            let m = input_action.on(ctx.buf, ctx.eof, "y")?;
            if m.is_some() {
                if let Some(_a @ true) = ctx.state.wait_for_continue {
                    ctx.state.pressed_yes_on_continue = Some(true);
                }
            };

            let m = input_action.on(ctx.buf, ctx.eof, "n")?;
            if m.is_some() {
                if let Some(_a @ true) = ctx.state.wait_for_continue {
                    ctx.state.pressed_yes_on_continue = Some(false);
                }
            }

            Ok(false)
        });

    let mut session = spawn("python ./tests/source/ansi.py").expect("Can't spawn a session");

    let mut stdin = Stdin::open().unwrap();
    let stdout = std::io::stdout();

    let mut interact = session.interact(&mut stdin, stdout);

    let is_alive = interact.spawn(opts).expect("Failed to start interact");

    if !is_alive {
        println!("The process was exited");
        #[cfg(unix)]
        println!("Status={:?}", interact.get_status());
    }

    stdin.close().unwrap();

    println!("RESULTS");
    println!(
        "Number of time 'Y' was pressed = {}",
        state.pressed_yes_on_continue.unwrap_or_default()
    );
    println!(
        "Status counter = {}",
        state.stutus_verification_counter.unwrap_or_default()
    );
}

Trait Implementations§

source§

impl<P: Debug, S: Debug> Debug for ReplSession<P, S>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<P, S> Deref for ReplSession<P, S>

§

type Target = Session<P, S>

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl<P, S> DerefMut for ReplSession<P, S>

source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.

Auto Trait Implementations§

§

impl<P, S> RefUnwindSafe for ReplSession<P, S>where P: RefUnwindSafe, S: RefUnwindSafe,

§

impl<P, S> Send for ReplSession<P, S>where P: Send, S: Send,

§

impl<P, S> Sync for ReplSession<P, S>where P: Sync, S: Sync,

§

impl<P, S> Unpin for ReplSession<P, S>where P: Unpin, S: Unpin,

§

impl<P, S> UnwindSafe for ReplSession<P, S>where P: UnwindSafe, S: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.