creator_tools/
error.rs

1//! Contains `Error`, `AndroidError`, `AppleError` types used by `creator-tools`.
2
3use apple_bundle::plist;
4use displaydoc::Display;
5use std::path::PathBuf;
6use std::process::Command;
7use thiserror::Error;
8
9/// `Result` type that used in `creator-tools`.
10pub type Result<T> = std::result::Result<T, Error>;
11
12/// Android specific error type
13#[derive(Display, Debug, Error)]
14pub enum AndroidError {
15    /// Android SDK is not found
16    AndroidSdkNotFound,
17    /// Android NDK is not found
18    AndroidNdkNotFound,
19    /// Android SDK has no build tools
20    BuildToolsNotFound,
21    /// Android SDK has no platforms installed
22    NoPlatformsFound,
23    /// Platform {0} is not installed
24    PlatformNotFound(u32),
25    /// Target is not supported
26    UnsupportedTarget,
27    /// Host {0} is not supported
28    UnsupportedHost(String),
29    /// Invalid semver
30    InvalidSemver,
31    /// Unsupported or invalid target: {0}
32    InvalidBuildTarget(String),
33    /// Failed to find AndroidManifest.xml in path: {0}
34    FailedToFindAndroidManifest(String),
35    /// AndroidManifest error
36    AndroidManifest(#[from] android_manifest::error::Error),
37}
38
39/// Apple specific error type.
40#[derive(Display, Debug, Error)]
41pub enum AppleError {
42    /// Code signing profile not found
43    CodeSigningProfilesNotFound,
44    /// Code signing profile not provided
45    CodeSigningProfileNotProvided,
46    /// Codesign failed {0}
47    CodesignFailed(String),
48    /// Failed to archive payload
49    ZipCommandFailed,
50    /// Codesign allocate not found
51    CodesignAllocateNotFound,
52    /// Simctl error
53    Simctl(simctl::Error),
54    /// Target dir does not exists
55    TargetNotFound,
56    /// Resources dir does not exists
57    ResourcesNotFound,
58    /// Assets dir does not exists
59    AssetsNotFound,
60    /// Failed to find Info.plist in path: {0}
61    FailedToFindInfoPlist(String),
62    /// Plist data error
63    Plist(#[from] plist::Error),
64}
65
66/// Main error type.
67#[derive(Display, Debug, Error)]
68pub enum Error {
69    /// Command '{0:?}' had a non-zero exit code. Stdout: {1} Stderr: {2}
70    CmdFailed(Command, String, String),
71    /// Command {0} not found
72    CmdNotFound(String),
73    /// Invalid profile: {0}
74    InvalidProfile(String),
75    /// Invalid interface orientation: {0:?}
76    InvalidInterfaceOrientation(String),
77    /// GNU toolchain binary `{gnu_bin}` nor LLVM toolchain binary `{llvm_bin}` found in
78    /// `{toolchain_path:?}`
79    ToolchainBinaryNotFound {
80        toolchain_path: PathBuf,
81        gnu_bin: String,
82        llvm_bin: String,
83    },
84    /// Path {0:?} doesn't exist
85    PathNotFound(PathBuf),
86    /// Failed to find cargo manifest: {0}
87    FailedToFindCargoManifest(String),
88    /// Failed to choose shell string color.
89    /// Argument for --color must be auto, always, or never, but found `{}`
90    FailedToChooseShellStringColor(String),
91    /// IO error
92    Io(#[from] std::io::Error),
93    /// FS Extra error
94    FsExtra(#[from] fs_extra::error::Error),
95    /// Android error
96    Android(#[from] AndroidError),
97    /// Apple error
98    Apple(#[from] AppleError),
99    /// Other error
100    OtherError(#[from] Box<dyn std::error::Error>),
101}
102
103/// Extension trait for [`Command`] that helps
104/// to wrap output and print logs from command execution.
105///
106/// [`Command`]: std::process::Command
107pub trait CommandExt {
108    /// Executes the command as a child process, then captures an output and return it.
109    /// If command termination wasn't successful wraps an output into error and return it.
110    fn output_err(self, print_logs: bool) -> Result<std::process::Output>;
111}
112
113impl CommandExt for Command {
114    fn output_err(mut self, print_logs: bool) -> Result<std::process::Output> {
115        // Enables log print during command execution
116        let output = match print_logs {
117            true => self.spawn().and_then(|p| p.wait_with_output())?,
118            false => self.output()?,
119        };
120        if !output.status.success() {
121            return Err(Error::CmdFailed(
122                self,
123                String::from_utf8_lossy(&output.stdout).to_string(),
124                String::from_utf8_lossy(&output.stderr).to_string(),
125            ));
126        }
127        Ok(output)
128    }
129}
130
131impl From<plist::Error> for Error {
132    fn from(error: plist::Error) -> Self {
133        AppleError::from(error).into()
134    }
135}
136
137impl From<simctl::Error> for Error {
138    fn from(error: simctl::Error) -> Self {
139        AppleError::Simctl(error).into()
140    }
141}