Skip to main content

kawauso_process/error/
run.rs

1//! The error of running a command
2
3use thiserror::Error;
4
5use crate::invocation::Invocation;
6
7/// The error returned when a command does not run
8///
9/// The variants separate what happened to the command. A command that never
10/// started needs a program that exists, a working directory that exists, and
11/// the rights to start a program. A run that started and did not finish means
12/// that the operating system stopped the crate from collecting the result,
13/// which a caller reports and can try again.
14///
15/// A command that ran and ended without success is no failure of the run. The
16/// result then carries the status, and the caller decides what it means.
17///
18/// A later release can add variants, and it can add fields to a variant.
19/// Match with a wildcard arm, and bind the fields of a variant with `..`.
20#[derive(Debug, Error)]
21#[non_exhaustive]
22pub enum RunCommandError {
23    /// The command started and the run did not finish
24    ///
25    /// The program ran, and reading one of its streams or waiting for its end
26    /// failed. Nothing of the run survives such a failure, so the crate
27    /// reports it instead of a result with holes in it. The command itself
28    /// can still have done its work.
29    // process[impl run.error.message]
30    #[error("failed to complete the run of the command `{invocation}`")]
31    #[non_exhaustive]
32    IncompleteRun {
33        /// The command that did not finish
34        invocation: Invocation,
35
36        /// The cause of the failure
37        source: std::io::Error,
38    },
39
40    /// The command did not start
41    ///
42    /// No program answers to the name, the working directory does not exist,
43    /// or the operating system refused to start the program. Nothing ran, so
44    /// there is no status and no output to report.
45    // process[impl run.error]
46    // process[impl run.error.message]
47    #[error("failed to start the command `{invocation}`")]
48    #[non_exhaustive]
49    UnstartableCommand {
50        /// The command that did not start
51        invocation: Invocation,
52
53        /// The cause of the failure
54        source: std::io::Error,
55    },
56}
57
58#[cfg(test)]
59mod tests {
60    // An assertion in a test panics by design. A `# Panics` section on every
61    // test would repeat that and give the reader no information.
62    #![allow(clippy::missing_panics_doc)]
63
64    use super::*;
65
66    // A caller sends the error between threads and keeps it in a report that
67    // another thread reads. This test holds the error to the auto traits that
68    // make this possible, because a private field of a later version could
69    // take them away without a word from the compiler.
70    #[test]
71    fn run_command_error_is_send_and_sync() {
72        fn assert_send_and_sync<T: Send + Sync>() {}
73
74        assert_send_and_sync::<RunCommandError>();
75    }
76}