android_tools_rs/
error.rs

1//! Contains `Error` type and `CommandExt` impl used by `android-tools-rs`.
2
3use displaydoc::Display;
4use std::process::Command;
5use thiserror::Error;
6
7/// `Result` type that used in `crossbundle-tools`.
8pub type Result<T> = std::result::Result<T, Error>;
9
10/// Main error type.
11#[derive(Display, Debug, Error)]
12#[ignore_extra_doc_attributes]
13pub enum Error {
14    /// Command '{0:?}' had a non-zero exit code. Stdout: {1} Stderr: {2}
15    CmdFailed(Command, String, String),
16    /// Bundletool is not found
17    BundletoolNotFound,
18    /// IO error
19    Io(#[from] std::io::Error),
20    /// Other error
21    OtherError(#[from] Box<dyn std::error::Error>),
22}
23
24/// Extension trait for [`Command`] that helps
25/// to wrap output and print logs from command execution.
26///
27/// [`Command`]: std::process::Command
28pub trait CommandExt {
29    /// Executes the command as a child process, then captures an output and return it.
30    /// If command termination wasn't successful wraps an output into error and return it.
31    fn output_err(self, print_logs: bool) -> Result<std::process::Output>;
32}
33
34impl CommandExt for Command {
35    fn output_err(mut self, print_logs: bool) -> Result<std::process::Output> {
36        // Enables log print during command execution
37        let output = match print_logs {
38            true => self.spawn().and_then(|p| p.wait_with_output())?,
39            false => self.output()?,
40        };
41        if !output.status.success() {
42            return Err(Error::CmdFailed(
43                self,
44                String::from_utf8_lossy(&output.stdout).to_string(),
45                String::from_utf8_lossy(&output.stderr).to_string(),
46            ));
47        }
48        Ok(output)
49    }
50}