use crate::{
apple::{
config::Config,
deps::{GemCache, IOS_DEPLOY_PACKAGE, LIBIMOBILE_DEVICE_PACKAGE},
},
env::{Env, ExplicitEnv as _},
opts::NoiseLevel,
util::cli::{Report, Reportable},
DuctExpressionExt,
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum RunAndDebugError {
#[error("Failed to run {command}: {error}")]
CommandFailed {
command: String,
error: std::io::Error,
},
}
impl Reportable for RunAndDebugError {
fn report(&self) -> Report {
match self {
Self::CommandFailed { command, error } => {
Report::error(format!("Failed to run {command}"), error)
}
}
}
}
pub fn run_and_debug(
config: &Config,
env: &Env,
non_interactive: bool,
id: &str,
noise_level: NoiseLevel,
) -> Result<duct::Handle, RunAndDebugError> {
println!("Deploying app to device...");
IOS_DEPLOY_PACKAGE
.install(false, &mut GemCache::new())
.map_err(|e| RunAndDebugError::CommandFailed {
command: "`brew install ios-deploy`".to_string(),
error: std::io::Error::other(e.to_string()),
})?;
let app_path = config.app_path();
let deploy_cmd = duct::cmd("ios-deploy", ["--debug", "--id", id, "--no-wifi"])
.vars(env.explicit_env())
.before_spawn(move |cmd| {
cmd.arg("--bundle").arg(&app_path);
if non_interactive {
cmd.arg("--noninteractive");
} else {
cmd.arg("--justlaunch");
}
Ok(())
})
.dup_stdio();
if non_interactive {
Ok(deploy_cmd
.start()
.map_err(|error| RunAndDebugError::CommandFailed {
command: format!("{deploy_cmd:?}"),
error,
})?)
} else {
deploy_cmd
.start()
.map_err(|error| RunAndDebugError::CommandFailed {
command: format!("{deploy_cmd:?}"),
error,
})?
.wait()
.map_err(|error| RunAndDebugError::CommandFailed {
command: format!("{deploy_cmd:?}"),
error,
})?;
let app_name = config.app().stylized_name().to_string();
LIBIMOBILE_DEVICE_PACKAGE
.install(false, &mut GemCache::new())
.map_err(|e| RunAndDebugError::CommandFailed {
command: "`brew install libimobiledevice`".to_string(),
error: std::io::Error::other(e.to_string()),
})?;
let cmd = duct::cmd("idevicesyslog", ["--process", &app_name])
.before_spawn(move |cmd| {
if !noise_level.pedantic() {
cmd.arg("--match").arg(format!("{app_name}["));
}
Ok(())
})
.vars(env.explicit_env())
.dup_stdio();
cmd.start()
.map_err(|error| RunAndDebugError::CommandFailed {
command: format!("{cmd:?}"),
error,
})
}
}