|
1 | | -use anyhow::Context; |
2 | | -use std::env; |
3 | | -use std::ffi::{OsStr, OsString}; |
4 | | -use std::path::PathBuf; |
5 | | -use std::process::{Command, Stdio}; |
| 1 | +use shared::command::{CommandError, CommandExt}; |
| 2 | +use std::process::Output; |
| 3 | +use std::{ |
| 4 | + env, |
| 5 | + ffi::OsStr, |
| 6 | + process::{Command, Stdio}, |
| 7 | +}; |
| 8 | +use thiserror::Error; |
| 9 | + |
| 10 | +/// Represents possible errors when working with USC commands. |
| 11 | +
|
| 12 | +#[derive(Debug, Error)] |
| 13 | +pub enum USCError { |
| 14 | + #[error( |
| 15 | + "`universal-sierra-compiler` binary not available. \ |
| 16 | + Make sure it is installed and available in PATH or set via UNIVERSAL_SIERRA_COMPILER." |
| 17 | + )] |
| 18 | + NotFound(#[source] which::Error), |
| 19 | + |
| 20 | + #[error( |
| 21 | + "Error while compiling Sierra. \ |
| 22 | + Make sure you have the latest universal-sierra-compiler binary installed. \ |
| 23 | + Contact us if it doesn't help." |
| 24 | + )] |
| 25 | + RunFailed(#[source] CommandError), |
| 26 | +} |
6 | 27 |
|
7 | 28 | /// A builder for `universal-sierra-compiler` command invocation. |
8 | | -#[derive(Clone, Debug, Default)] |
9 | | -pub struct UniversalSierraCompilerCommand { |
10 | | - args: Vec<OsString>, |
11 | | - current_dir: Option<PathBuf>, |
12 | | - inherit_stderr: bool, |
| 29 | +#[derive(Debug)] |
| 30 | +pub struct USCInternalCommand { |
| 31 | + inner: Command, |
13 | 32 | } |
14 | 33 |
|
15 | | -impl UniversalSierraCompilerCommand { |
| 34 | +impl USCInternalCommand { |
16 | 35 | /// Creates a default `universal-sierra-compiler` command, |
17 | 36 | /// which will look for `universal-sierra-compiler` in `$PATH` |
18 | | - #[must_use] |
19 | | - pub fn new() -> Self { |
20 | | - Self::default() |
21 | | - } |
22 | | - |
23 | | - /// Ensures that `universal-sierra-compiler` binary is available in the system. |
24 | | - pub fn ensure_available() -> anyhow::Result<()> { |
25 | | - which::which(UniversalSierraCompilerCommand::binary_path()) |
26 | | - .context("Cannot find `universal-sierra-compiler` binary. \ |
27 | | - Make sure you have USC installed https://github.com/software-mansion/universal-sierra-compiler \ |
28 | | - and added to PATH (or set at UNIVERSAL_SIERRA_COMPILER env var)" |
29 | | - )?; |
30 | | - Ok(()) |
31 | | - } |
32 | | - |
33 | | - /// Current directory of the `universal-sierra-compiler` process. |
34 | | - pub fn current_dir(&mut self, path: impl Into<PathBuf>) -> &mut Self { |
35 | | - self.current_dir = Some(path.into()); |
36 | | - self |
37 | | - } |
38 | | - |
39 | | - /// Inherit standard error, i.e. show USC errors in this process's standard error. |
40 | | - pub fn inherit_stderr(&mut self) -> &mut Self { |
41 | | - self.inherit_stderr = true; |
42 | | - self |
| 37 | + pub fn new() -> Result<Self, USCError> { |
| 38 | + ensure_available()?; |
| 39 | + let mut cmd = Command::new(binary_path()); |
| 40 | + cmd.stderr(Stdio::inherit()); |
| 41 | + Ok(Self { inner: cmd }) |
43 | 42 | } |
44 | 43 |
|
45 | 44 | /// Adds an argument to pass to `universal-sierra-compiler`. |
46 | | - pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self { |
47 | | - self.args.push(arg.as_ref().to_os_string()); |
48 | | - self |
49 | | - } |
50 | | - |
51 | | - /// Adds multiple arguments to pass to `universal-sierra-compiler`. |
52 | | - pub fn args<I, S>(&mut self, args: I) -> &mut Self |
53 | | - where |
54 | | - I: IntoIterator<Item = S>, |
55 | | - S: AsRef<OsStr>, |
56 | | - { |
57 | | - self.args |
58 | | - .extend(args.into_iter().map(|s| s.as_ref().to_os_string())); |
| 45 | + pub fn arg(mut self, arg: impl AsRef<OsStr>) -> Self { |
| 46 | + self.inner.arg(arg); |
59 | 47 | self |
60 | 48 | } |
61 | 49 |
|
62 | 50 | /// Build executable `universal-sierra-compiler` command. |
63 | 51 | #[must_use] |
64 | | - pub fn command(&self) -> Command { |
65 | | - let universal_sierra_compiler = UniversalSierraCompilerCommand::binary_path(); |
66 | | - |
67 | | - let mut cmd = Command::new(universal_sierra_compiler); |
68 | | - |
69 | | - cmd.args(&self.args); |
70 | | - |
71 | | - if let Some(path) = &self.current_dir { |
72 | | - cmd.current_dir(path); |
73 | | - } |
74 | | - |
75 | | - if self.inherit_stderr { |
76 | | - cmd.stderr(Stdio::inherit()); |
77 | | - } |
78 | | - |
79 | | - cmd |
| 52 | + pub fn command(self) -> Command { |
| 53 | + self.inner |
80 | 54 | } |
81 | 55 |
|
82 | | - fn binary_path() -> PathBuf { |
83 | | - env::var("UNIVERSAL_SIERRA_COMPILER") |
84 | | - .map(PathBuf::from) |
85 | | - .ok() |
86 | | - .unwrap_or_else(|| PathBuf::from("universal-sierra-compiler")) |
| 56 | + pub fn run(self) -> Result<Output, USCError> { |
| 57 | + self.command().output_checked().map_err(USCError::RunFailed) |
87 | 58 | } |
88 | 59 | } |
| 60 | + |
| 61 | +/// Ensures that `universal-sierra-compiler` binary is available in the system. |
| 62 | +pub fn ensure_available() -> Result<(), USCError> { |
| 63 | + which::which(binary_path()) |
| 64 | + .map(|_| ()) |
| 65 | + .map_err(USCError::NotFound) |
| 66 | +} |
| 67 | + |
| 68 | +/// Returns the binary path either from env or fallback to default name. |
| 69 | +fn binary_path() -> String { |
| 70 | + env::var("UNIVERSAL_SIERRA_COMPILER") |
| 71 | + .unwrap_or_else(|_| "universal-sierra-compiler".to_string()) |
| 72 | +} |
0 commit comments