Skip to content

Commit

Permalink
Replace error-chain with thiserror
Browse files Browse the repository at this point in the history
This patch replaces error-chain with the current version of thiserror.
There's nothing done more, so no cleanup of .expect() or .unwrap()
calls, just a plain conversion from one crate to another.

Signed-off-by: Matthias Beyer <[email protected]>
  • Loading branch information
matthiasbeyer committed Sep 12, 2022
1 parent 9b3884e commit 0cddb83
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 110 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ readme = "README.md"
[dependencies]
nix = "0.14"
regex = "1"
error-chain = "0.12"
tempfile = "3"
thiserror = "1.0.34"

[badges]
maintenance = { status = "passively-maintained" }
62 changes: 36 additions & 26 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
use std::time;

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_millis())
}
EmptyProgramName {
description("The provided program name is empty.")
display("EmptyProgramName")
}
}
#[derive(Debug, thiserror::Error)]
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_string()))]
EOF {
expected: String,
got: String,
exit_code: Option<String>,
},

#[error("PipeError")]
BrokenPipe,

#[error("Timeout Error: Expected {} but got \"{}\" (after waiting {} ms)", .expected, .got, (.timeout.as_secs() * 1000) as u32 + .timeout.subsec_millis())]
Timeout {
expected: String,
got: String,
timeout: time::Duration,
},

#[error("The provided program name is empty.")]
EmptyProgramName,

#[error(transparent)]
Nix(#[from] nix::Error),

#[error(transparent)]
Io(#[from] std::io::Error),

#[error("Did not understand Ctrl-{}", .0)]
SendContolError(char),

#[error("Failed to send via MPSC channel")]
MpscSendError,

#[error(transparent)]
Regex(#[from] regex::Error),
}
27 changes: 13 additions & 14 deletions src/process.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Start a process via pty
use crate::error::*;
use crate::error::Error;
use nix;
use nix::fcntl::{open, OFlag};
use nix::libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
Expand All @@ -13,7 +13,7 @@ use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::os::unix::process::CommandExt;
use std::process::Command;
use std::{thread, time}; // load error-chain
use std::{thread, time};

/// Start a process in a forked tty so you can interact with it the same as you would
/// within a terminal
Expand Down Expand Up @@ -87,7 +87,7 @@ fn ptsname_r(fd: &PtyMaster) -> nix::Result<String> {

impl PtyProcess {
/// Start a process in a forked pty
pub fn new(mut command: Command) -> Result<Self> {
pub fn new(mut command: Command) -> Result<Self, Error> {
|| -> nix::Result<Self> {
// Open a new PTY master
let master_fd = posix_openpt(OFlag::O_RDWR)?;
Expand Down Expand Up @@ -128,7 +128,7 @@ impl PtyProcess {
}),
}
}()
.chain_err(|| format!("could not execute {:?}", command))
.map_err(Error::from)
}

/// Get handle to pty fork for reading/writing
Expand Down Expand Up @@ -177,19 +177,18 @@ impl PtyProcess {

/// Wait until process has exited. This is a blocking call.
/// If the process doesn't terminate this will block forever.
pub fn wait(&self) -> Result<wait::WaitStatus> {
wait::waitpid(self.child_pid, None).chain_err(|| "wait: cannot read status")
pub fn wait(&self) -> Result<wait::WaitStatus, Error> {
wait::waitpid(self.child_pid, None).map_err(Error::from)
}

/// Regularly exit the process, this method is blocking until the process is dead
pub fn exit(&mut self) -> Result<wait::WaitStatus> {
self.kill(signal::SIGTERM)
pub fn exit(&mut self) -> Result<wait::WaitStatus, Error> {
self.kill(signal::SIGTERM).map_err(Error::from)
}

/// Non-blocking variant of `kill()` (doesn't wait for process to be killed)
pub fn signal(&mut self, sig: signal::Signal) -> Result<()> {
signal::kill(self.child_pid, sig).chain_err(|| "failed to send signal to process")?;
Ok(())
pub fn signal(&mut self, sig: signal::Signal) -> Result<(), Error> {
signal::kill(self.child_pid, sig).map_err(Error::from)
}

/// Kill the process with a specific signal. This method blocks, until the process is dead
Expand All @@ -200,7 +199,7 @@ impl PtyProcess {
///
/// if `kill_timeout` is set and a repeated sending of signal does not result in the process
/// being killed, then `kill -9` is sent after the `kill_timeout` duration has elapsed.
pub fn kill(&mut self, sig: signal::Signal) -> Result<wait::WaitStatus> {
pub fn kill(&mut self, sig: signal::Signal) -> Result<wait::WaitStatus, Error> {
let start = time::Instant::now();
loop {
match signal::kill(self.child_pid, sig) {
Expand All @@ -209,7 +208,7 @@ impl PtyProcess {
Err(nix::Error::Sys(nix::errno::Errno::ESRCH)) => {
return Ok(wait::WaitStatus::Exited(Pid::from_raw(0), 0))
}
Err(e) => return Err(format!("kill resulted in error: {:?}", e).into()),
Err(e) => return Err(Error::from(e)),
}

match self.status() {
Expand All @@ -219,7 +218,7 @@ impl PtyProcess {
// kill -9 if timout is reached
if let Some(timeout) = self.kill_timeout {
if start.elapsed() > timeout {
signal::kill(self.child_pid, signal::Signal::SIGKILL).chain_err(|| "")?
signal::kill(self.child_pid, signal::Signal::SIGKILL).map_err(Error::from)?
}
}
}
Expand Down
35 changes: 20 additions & 15 deletions src/reader.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Unblocking reader which supports waiting for strings/regexes and EOF to be present
use crate::error::*; // load error-chain
use crate::error::Error;
pub use regex::Regex;
use std::io::prelude::*;
use std::io::{self, BufReader};
Expand Down Expand Up @@ -120,22 +120,23 @@ impl NBReader {

// spawn a thread which reads one char and sends it to tx
thread::spawn(move || {
let _ = || -> Result<()> {
let _ = || -> Result<(), Error> {
let mut reader = BufReader::new(f);
let mut byte = [0u8];
loop {
match reader.read(&mut byte) {
Ok(0) => {
tx.send(Ok(PipedChar::EOF)).chain_err(|| "cannot send")?;
tx.send(Ok(PipedChar::EOF))
.map_err(|_| Error::MpscSendError)?;
break;
}
Ok(_) => {
tx.send(Ok(PipedChar::Char(byte[0])))
.chain_err(|| "cannot send")?;
.map_err(|_| Error::MpscSendError)?;
}
Err(error) => {
tx.send(Err(PipeError::IO(error)))
.chain_err(|| "cannot send")?;
.map_err(|_| Error::MpscSendError)?;
}
}
}
Expand All @@ -155,7 +156,7 @@ impl NBReader {
}

/// reads all available chars from the read channel and stores them in self.buffer
fn read_into_buffer(&mut self) -> Result<()> {
fn read_into_buffer(&mut self) -> Result<(), Error> {
if self.eof {
return Ok(());
}
Expand Down Expand Up @@ -222,7 +223,7 @@ impl NBReader {
/// assert_eq!("?", &until_end);
/// ```
///
pub fn read_until(&mut self, needle: &ReadUntil) -> Result<(String, String)> {
pub fn read_until(&mut self, needle: &ReadUntil) -> Result<(String, String), Error> {
let start = time::Instant::now();

loop {
Expand All @@ -237,22 +238,26 @@ impl NBReader {
// we don't know the reason of eof yet, so we provide an empty string
// this will be filled out in session::exp()
if self.eof {
return Err(ErrorKind::EOF(needle.to_string(), self.buffer.clone(), None).into());
return Err(Error::EOF {
expected: needle.to_string(),
got: self.buffer.clone(),
exit_code: None,
});
}

// ran into timeout
if let Some(timeout) = self.timeout {
if start.elapsed() > timeout {
return Err(ErrorKind::Timeout(
needle.to_string(),
self.buffer
return Err(Error::Timeout {
expected: needle.to_string(),
got: self
.buffer
.clone()
.replace('\n', "`\\n`\n")
.replace('\r', "`\\r`")
.replace('\u{1b}', "`^`"),
timeout,
)
.into());
});
}
}
// nothing matched: wait a little
Expand Down Expand Up @@ -289,8 +294,8 @@ mod tests {
// check for EOF
match r.read_until(&ReadUntil::NBytes(10)) {
Ok(_) => panic!(),
Err(Error(ErrorKind::EOF(_, _, _), _)) => {}
Err(Error(_, _)) => panic!(),
Err(Error::EOF { .. }) => {}
Err(_) => panic!(),
}
}

Expand Down
Loading

0 comments on commit 0cddb83

Please sign in to comment.