diff --git a/tooling/cli/src/mobile/android.rs b/tooling/cli/src/mobile/android.rs index 407f623a6..6c1b17792 100644 --- a/tooling/cli/src/mobile/android.rs +++ b/tooling/cli/src/mobile/android.rs @@ -6,13 +6,12 @@ use cargo_mobile::{ android::{ adb, config::{Config as AndroidConfig, Metadata as AndroidMetadata, Raw as RawAndroidConfig}, - device::{Device, RunError}, - env::{Env, Error as AndroidEnvError}, - target::{BuildError, Target}, + device::Device, + env::Env, + target::Target, }, config::app::App, device::PromptError, - env::Error as EnvError, opts::NoiseLevel, os, util::prompt, @@ -36,34 +35,6 @@ mod dev; mod open; pub(crate) mod project; -#[derive(Debug, thiserror::Error)] -enum Error { - #[error(transparent)] - EnvInitFailed(EnvError), - #[error(transparent)] - AndroidEnvInitFailed(AndroidEnvError), - #[error(transparent)] - InitDotCargo(super::init::Error), - #[error("invalid tauri configuration: {0}")] - InvalidTauriConfig(String), - #[error("{0}")] - ProjectNotInitialized(String), - #[error(transparent)] - OpenFailed(os::OpenFileError), - #[error("{0}")] - DevFailed(String), - #[error("{0}")] - BuildFailed(String), - #[error(transparent)] - AndroidStudioScriptFailed(BuildError), - #[error(transparent)] - RunFailed(RunError), - #[error("{0}")] - TargetInvalid(String), - #[error(transparent)] - FailedToPromptForDevice(PromptError), -} - #[derive(Parser)] #[clap( author, @@ -138,11 +109,10 @@ pub fn get_config( fn with_config( cli_options: Option, - f: impl FnOnce(&App, &AndroidConfig, &AndroidMetadata, CliOptions) -> Result, -) -> Result { + f: impl FnOnce(&App, &AndroidConfig, &AndroidMetadata, CliOptions) -> Result, +) -> Result { let (app, config, metadata, cli_options) = { - let tauri_config = - get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?; + let tauri_config = get_tauri_config(None)?; let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap(); let cli_options = @@ -153,9 +123,9 @@ fn with_config( f(&app, &config, &metadata, cli_options) } -fn env() -> Result { - let env = super::env().map_err(Error::EnvInitFailed)?; - cargo_mobile::android::env::Env::from_env(env).map_err(Error::AndroidEnvInitFailed) +fn env() -> Result { + let env = super::env()?; + cargo_mobile::android::env::Env::from_env(env).map_err(Into::into) } fn delete_codegen_vars() { diff --git a/tooling/cli/src/mobile/android/android_studio_script.rs b/tooling/cli/src/mobile/android/android_studio_script.rs index 1c91f2f9f..cf3bc974a 100644 --- a/tooling/cli/src/mobile/android/android_studio_script.rs +++ b/tooling/cli/src/mobile/android/android_studio_script.rs @@ -1,4 +1,4 @@ -use super::{detect_target_ok, ensure_init, env, init_dot_cargo, with_config, Error, MobileTarget}; +use super::{detect_target_ok, ensure_init, env, init_dot_cargo, with_config, MobileTarget}; use crate::Result; use clap::Parser; @@ -33,11 +33,10 @@ pub fn command(options: Options) -> Result<()> { }; with_config(None, |app, config, metadata, cli_options| { - ensure_init(config.project_dir(), MobileTarget::Android) - .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; + ensure_init(config.project_dir(), MobileTarget::Android)?; let env = env()?; - init_dot_cargo(app, Some((&env, config))).map_err(Error::InitDotCargo)?; + init_dot_cargo(app, Some((&env, config)))?; call_for_targets_with_fallback( options.targets.unwrap_or_default().iter(), @@ -53,10 +52,9 @@ pub fn command(options: Options) -> Result<()> { true, profile, ) - .map_err(Error::AndroidStudioScriptFailed) + .map_err(Into::into) }, ) - .map_err(|e| Error::TargetInvalid(e.to_string()))? + .map_err(|e| anyhow::anyhow!(e.to_string()))? }) - .map_err(Into::into) } diff --git a/tooling/cli/src/mobile/android/build.rs b/tooling/cli/src/mobile/android/build.rs index 4b37173cc..482755720 100644 --- a/tooling/cli/src/mobile/android/build.rs +++ b/tooling/cli/src/mobile/android/build.rs @@ -1,6 +1,6 @@ use super::{ delete_codegen_vars, ensure_init, env, init_dot_cargo, log_finished, open_and_wait, with_config, - Error, MobileTarget, + MobileTarget, }; use crate::{ helpers::{config::get as get_tauri_config, flock}, @@ -75,15 +75,13 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { set_var("WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION", ""); set_var("WRY_RUSTWEBVIEW_CLASS_INIT", ""); - ensure_init(config.project_dir(), MobileTarget::Android) - .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; + ensure_init(config.project_dir(), MobileTarget::Android)?; let env = env()?; - init_dot_cargo(app, Some((&env, config))).map_err(Error::InitDotCargo)?; + init_dot_cargo(app, Some((&env, config)))?; let open = options.open; - run_build(options, config, &env, noise_level) - .map_err(|e| Error::BuildFailed(format!("{:#}", e)))?; + run_build(options, config, &env, noise_level)?; if open { open_and_wait(config, &env); @@ -176,7 +174,7 @@ fn run_build( Ok(()) } -fn get_targets_or_all<'a>(targets: Vec) -> Result>, Error> { +fn get_targets_or_all<'a>(targets: Vec) -> Result>> { if targets.is_empty() { Ok(Target::all().iter().map(|t| t.1).collect()) } else { @@ -190,10 +188,11 @@ fn get_targets_or_all<'a>(targets: Vec) -> Result>, E for t in targets { let target = Target::for_name(&t).ok_or_else(|| { - Error::TargetInvalid(format!( + anyhow::anyhow!( "Target {} is invalid; the possible targets are {}", - t, possible_targets - )) + t, + possible_targets + ) })?; outs.push(target); } diff --git a/tooling/cli/src/mobile/android/dev.rs b/tooling/cli/src/mobile/android/dev.rs index 66eaf1c12..d308886ef 100644 --- a/tooling/cli/src/mobile/android/dev.rs +++ b/tooling/cli/src/mobile/android/dev.rs @@ -1,6 +1,6 @@ use super::{ delete_codegen_vars, device_prompt, ensure_init, env, init_dot_cargo, open_and_wait, with_config, - Error, MobileTarget, + MobileTarget, PromptError, }; use crate::{ helpers::{config::get as get_tauri_config, flock}, @@ -12,7 +12,9 @@ use clap::Parser; use cargo_mobile::{ android::{ + adb, config::{Config as AndroidConfig, Metadata as AndroidMetadata}, + device::RunError as DeviceRunError, env::Env, }, config::app::App, @@ -75,10 +77,8 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { WEBVIEW_CLIENT_CLASS_EXTENSION, ); set_var("WRY_RUSTWEBVIEW_CLASS_INIT", WEBVIEW_CLASS_INIT); - ensure_init(config.project_dir(), MobileTarget::Android) - .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; - run_dev(options, app, config, metadata, noise_level) - .map_err(|e| Error::DevFailed(format!("{:#}", e))) + ensure_init(config.project_dir(), MobileTarget::Android)?; + run_dev(options, app, config, metadata, noise_level).map_err(Into::into) }, ) .map_err(Into::into) @@ -110,7 +110,7 @@ fn run_dev( let _lock = flock::open_rw(&out_dir.join("lock").with_extension("android"), "Android")?; let env = env()?; - init_dot_cargo(app, Some((&env, config))).map_err(Error::InitDotCargo)?; + init_dot_cargo(app, Some((&env, config)))?; let open = options.open; let exit_on_panic = options.exit_on_panic; @@ -142,7 +142,7 @@ fn run_dev( }); Ok(Box::new(c) as Box) } - Err(Error::FailedToPromptForDevice(e)) => { + Err(RunError::FailedToPromptForDevice(e)) => { log::error!("{}", e); open_and_wait(config, &env) } @@ -153,13 +153,21 @@ fn run_dev( ) } +#[derive(Debug, thiserror::Error)] +enum RunError { + #[error(transparent)] + FailedToPromptForDevice(PromptError), + #[error(transparent)] + RunFailed(DeviceRunError), +} + fn run( options: MobileOptions, config: &AndroidConfig, env: &Env, metadata: &AndroidMetadata, noise_level: NoiseLevel, -) -> Result { +) -> Result { let profile = if options.debug { Profile::Debug } else { @@ -169,7 +177,7 @@ fn run( let build_app_bundle = metadata.asset_packs().is_some(); device_prompt(env) - .map_err(Error::FailedToPromptForDevice)? + .map_err(RunError::FailedToPromptForDevice)? .run( config, env, @@ -181,5 +189,5 @@ fn run( ".MainActivity".into(), ) .map(DevChild::new) - .map_err(Error::RunFailed) + .map_err(RunError::RunFailed) } diff --git a/tooling/cli/src/mobile/android/open.rs b/tooling/cli/src/mobile/android/open.rs index f4f147ad9..b67c2aaec 100644 --- a/tooling/cli/src/mobile/android/open.rs +++ b/tooling/cli/src/mobile/android/open.rs @@ -1,4 +1,4 @@ -use super::{ensure_init, env, with_config, Error, MobileTarget}; +use super::{ensure_init, env, with_config, MobileTarget}; use crate::Result; use cargo_mobile::os; @@ -6,12 +6,9 @@ pub fn command() -> Result<()> { with_config( Some(Default::default()), |_root_conf, config, _metadata, _cli_options| { - ensure_init(config.project_dir(), MobileTarget::Android) - .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; + ensure_init(config.project_dir(), MobileTarget::Android)?; let env = env()?; - os::open_file_with("Android Studio", config.project_dir(), &env.base) - .map_err(Error::OpenFailed) + os::open_file_with("Android Studio", config.project_dir(), &env.base).map_err(Into::into) }, ) - .map_err(Into::into) } diff --git a/tooling/cli/src/mobile/android/project.rs b/tooling/cli/src/mobile/android/project.rs index c40c54a84..9182c7c8e 100644 --- a/tooling/cli/src/mobile/android/project.rs +++ b/tooling/cli/src/mobile/android/project.rs @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::helpers::template; +use crate::{helpers::template, Result}; +use anyhow::Context; use cargo_mobile::{ android::{ config::{Config, Metadata}, target::Target, }, - bossy, os, + os, target::TargetTrait as _, util::{ self, @@ -19,45 +20,18 @@ use cargo_mobile::{ use handlebars::Handlebars; use include_dir::{include_dir, Dir}; -use std::{ - ffi::OsStr, - fs, - path::{Path, PathBuf}, -}; +use std::{ffi::OsStr, fs, path::Path}; const TEMPLATE_DIR: Dir<'_> = include_dir!("templates/mobile/android"); -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("failed to run rustup: {0}")] - RustupFailed(bossy::Error), - #[error("failed to process template: {0}")] - TemplateProcessingFailed(String), - #[error("failed to create directory at {path}: {cause}")] - DirectoryCreationFailed { - path: PathBuf, - cause: std::io::Error, - }, - #[error("failed to symlink asset directory")] - AssetDirSymlinkFailed, - #[error("failed to copy {src} to {dest}: {cause}")] - FileCopyFailed { - src: PathBuf, - dest: PathBuf, - cause: std::io::Error, - }, - #[error("asset source {0} is invalid")] - AssetSourceInvalid(PathBuf), -} - pub fn gen( config: &Config, metadata: &Metadata, (handlebars, mut map): (Handlebars, template::JsonMap), wrapper: &TextWrapper, -) -> Result<(), Error> { +) -> Result<()> { println!("Installing Android toolchains..."); - Target::install_all().map_err(Error::RustupFailed)?; + Target::install_all().with_context(|| "failed to run rustup")?; println!("Generating Android Studio project..."); let dest = config.project_dir(); let asset_packs = metadata.asset_packs().unwrap_or_default(); @@ -143,7 +117,7 @@ pub fn gen( options.create_new(true).write(true).open(path) }, ) - .map_err(|e| Error::TemplateProcessingFailed(e.to_string()))?; + .with_context(|| "failed to process template")?; if !asset_packs.is_empty() { Report::action_request( @@ -157,23 +131,27 @@ pub fn gen( let source_src = config.app().root_dir().join(&source); let source_file = source_src .file_name() - .ok_or_else(|| Error::AssetSourceInvalid(source_src.clone()))?; + .ok_or_else(|| anyhow::anyhow!("asset source {} is invalid", source_src.display()))?; fs::copy(&source_src, source_dest.join(source_file)).map_err(|cause| { - Error::FileCopyFailed { - src: source_src, - dest: source_dest.clone(), - cause, - } + anyhow::anyhow!( + "failed to copy {} to {}: {}", + source_src.display(), + source_dest.display(), + cause + ) })?; } let dest = prefix_path(dest, "app/src/main/"); - fs::create_dir_all(&dest).map_err(|cause| Error::DirectoryCreationFailed { - path: dest.clone(), - cause, + fs::create_dir_all(&dest).map_err(|cause| { + anyhow::anyhow!( + "failed to create directory at {}: {}", + dest.display(), + cause + ) })?; os::ln::force_symlink_relative(config.app().asset_dir(), dest, ln::TargetStyle::Directory) - .map_err(|_| Error::AssetDirSymlinkFailed)?; + .map_err(|_| anyhow::anyhow!("failed to symlink asset directory"))?; Ok(()) } diff --git a/tooling/cli/src/mobile/init.rs b/tooling/cli/src/mobile/init.rs index 13204def5..26838e2b6 100644 --- a/tooling/cli/src/mobile/init.rs +++ b/tooling/cli/src/mobile/init.rs @@ -7,10 +7,8 @@ use crate::helpers::{config::get as get_tauri_config, template::JsonMap}; use crate::Result; use cargo_mobile::{ android::{ - self, config::Config as AndroidConfig, env::Env as AndroidEnv, ndk, - target::Target as AndroidTarget, + config::Config as AndroidConfig, env::Env as AndroidEnv, target::Target as AndroidTarget, }, - bossy, config::app::App, dot_cargo, os::code_command, @@ -23,7 +21,7 @@ use cargo_mobile::{ use clap::Parser; use handlebars::{Context, Handlebars, Helper, HelperResult, Output, RenderContext, RenderError}; -use std::{env::current_dir, fs, io, path::PathBuf}; +use std::{env::current_dir, fs, path::PathBuf}; #[derive(Debug, Parser)] #[clap(about = "Initializes a Tauri Android project")] @@ -41,39 +39,8 @@ pub fn command(mut options: Options, target: Target) -> Result<()> { Ok(()) } -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("invalid tauri configuration: {0}")] - InvalidTauriConfig(String), - #[error("failed to create asset dir {asset_dir}: {cause}")] - AssetDirCreation { - asset_dir: PathBuf, - cause: io::Error, - }, - #[error("failed to install LLDB VS Code extension: {0}")] - LldbExtensionInstall(bossy::Error), - #[error(transparent)] - DotCargoLoad(dot_cargo::LoadError), - #[error(transparent)] - DotCargoGenFailed(ndk::MissingToolError), - #[error(transparent)] - HostTargetTripleDetection(util::HostTargetTripleError), - #[cfg(target_os = "macos")] - #[error(transparent)] - IosInit(super::ios::project::Error), - #[error(transparent)] - AndroidEnv(android::env::Error), - #[error(transparent)] - AndroidInit(super::android::project::Error), - #[error(transparent)] - DotCargoWrite(dot_cargo::WriteError), -} - -pub fn init_dot_cargo( - app: &App, - android: Option<(&AndroidEnv, &AndroidConfig)>, -) -> Result<(), Error> { - let mut dot_cargo = dot_cargo::DotCargo::load(app).map_err(Error::DotCargoLoad)?; +pub fn init_dot_cargo(app: &App, android: Option<(&AndroidEnv, &AndroidConfig)>) -> Result<()> { + let mut dot_cargo = dot_cargo::DotCargo::load(app)?; // Mysteriously, builds that don't specify `--target` seem to fight over // the build cache with builds that use `--target`! This means that // alternating between i.e. `cargo run` and `cargo apple run` would @@ -84,21 +51,18 @@ pub fn init_dot_cargo( // // This behavior could be explained here: // https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags - dot_cargo - .set_default_target(util::host_target_triple().map_err(Error::HostTargetTripleDetection)?); + dot_cargo.set_default_target(util::host_target_triple()?); if let Some((env, config)) = android { for target in AndroidTarget::all().values() { dot_cargo.insert_target( target.triple.to_owned(), - target - .generate_cargo_config(config, env) - .map_err(Error::DotCargoGenFailed)?, + target.generate_cargo_config(config, env)?, ); } } - dot_cargo.write(app).map_err(Error::DotCargoWrite) + dot_cargo.write(app).map_err(Into::into) } pub fn exec( @@ -107,9 +71,8 @@ pub fn exec( non_interactive: bool, skip_dev_tools: bool, #[allow(unused_variables)] reinstall_deps: bool, -) -> Result { - let tauri_config = - get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?; +) -> Result { + let tauri_config = get_tauri_config(None)?; let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap(); @@ -117,7 +80,12 @@ pub fn exec( let asset_dir = app.asset_dir(); if !asset_dir.is_dir() { - fs::create_dir_all(&asset_dir).map_err(|cause| Error::AssetDirCreation { asset_dir, cause })?; + fs::create_dir_all(&asset_dir).map_err(|cause| { + anyhow::anyhow!( + "failed to create asset dir {path}: {cause}", + path = asset_dir.display() + ) + })?; } if !skip_dev_tools && util::command_present("code").unwrap_or_default() { let mut command = code_command(); @@ -125,9 +93,7 @@ pub fn exec( if non_interactive { command.add_arg("--force"); } - command - .run_and_wait() - .map_err(Error::LldbExtensionInstall)?; + command.run_and_wait()?; } let (handlebars, mut map) = handlebars(&app); @@ -173,8 +139,7 @@ pub fn exec( let (app, config, metadata) = super::android::get_config(Some(app), tauri_config_, &Default::default()); map.insert("android", &config); - super::android::project::gen(&config, &metadata, (handlebars, map), wrapper) - .map_err(Error::AndroidInit)?; + super::android::project::gen(&config, &metadata, (handlebars, map), wrapper)?; init_dot_cargo(&app, Some((&env, &config)))?; app } @@ -188,7 +153,7 @@ pub fn exec( init_dot_cargo(&app, None)?; app } else { - return Err(Error::AndroidEnv(err)); + return Err(err.into()); } } }, @@ -206,8 +171,7 @@ pub fn exec( non_interactive, skip_dev_tools, reinstall_deps, - ) - .map_err(Error::IosInit)?; + )?; init_dot_cargo(&app, None)?; app } diff --git a/tooling/cli/src/mobile/ios.rs b/tooling/cli/src/mobile/ios.rs index e37de65dd..907bfaf6b 100644 --- a/tooling/cli/src/mobile/ios.rs +++ b/tooling/cli/src/mobile/ios.rs @@ -8,15 +8,15 @@ use cargo_mobile::{ Config as AppleConfig, Metadata as AppleMetadata, Platform as ApplePlatform, Raw as RawAppleConfig, }, - device::{Device, RunError}, + device::Device, ios_deploy, - target::{CompileLibError, Target}, + target::Target, }, config::app::App, device::PromptError, - env::{Env, Error as EnvError}, + env::Env, opts::NoiseLevel, - os, util, + os, util::prompt, }; use clap::{Parser, Subcommand}; @@ -31,50 +31,12 @@ use crate::{ Result, }; -use std::path::PathBuf; - mod build; mod dev; mod open; pub(crate) mod project; mod xcode_script; -#[derive(Debug, thiserror::Error)] -enum Error { - #[error(transparent)] - EnvInitFailed(#[from] EnvError), - #[error(transparent)] - InitDotCargo(super::init::Error), - #[error("invalid tauri configuration: {0}")] - InvalidTauriConfig(String), - #[error("{0}")] - ProjectNotInitialized(String), - #[error(transparent)] - OpenFailed(os::OpenFileError), - #[error("{0}")] - DevFailed(String), - #[error("{0}")] - BuildFailed(String), - #[error(transparent)] - NoHomeDir(util::NoHomeDir), - #[error("SDK root provided by Xcode was invalid. {sdk_root} doesn't exist or isn't a directory")] - SdkRootInvalid { sdk_root: PathBuf }, - #[error("Include dir was invalid. {include_dir} doesn't exist or isn't a directory")] - IncludeDirInvalid { include_dir: PathBuf }, - #[error("macOS SDK root was invalid. {macos_sdk_root} doesn't exist or isn't a directory")] - MacosSdkRootInvalid { macos_sdk_root: PathBuf }, - #[error("Arch specified by Xcode was invalid. {arch} isn't a known arch")] - ArchInvalid { arch: String }, - #[error(transparent)] - CompileLibFailed(CompileLibError), - #[error(transparent)] - FailedToPromptForDevice(PromptError), - #[error(transparent)] - RunFailed(RunError), - #[error("{0}")] - TargetInvalid(String), -} - #[derive(Parser)] #[clap( author, @@ -146,11 +108,10 @@ pub fn get_config( fn with_config( cli_options: Option, - f: impl FnOnce(&App, &AppleConfig, &AppleMetadata, CliOptions) -> Result, -) -> Result { + f: impl FnOnce(&App, &AppleConfig, &AppleMetadata, CliOptions) -> Result, +) -> Result { let (app, config, metadata, cli_options) = { - let tauri_config = - get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?; + let tauri_config = get_tauri_config(None)?; let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap(); let cli_options = cli_options.unwrap_or_else(|| read_options(tauri_config_, MobileTarget::Ios)); diff --git a/tooling/cli/src/mobile/ios/build.rs b/tooling/cli/src/mobile/ios/build.rs index be6a21437..9f771eed9 100644 --- a/tooling/cli/src/mobile/ios/build.rs +++ b/tooling/cli/src/mobile/ios/build.rs @@ -1,6 +1,6 @@ use super::{ detect_target_ok, ensure_init, env, init_dot_cargo, log_finished, open_and_wait, with_config, - Error, MobileTarget, + MobileTarget, }; use crate::{ helpers::{config::get as get_tauri_config, flock}, @@ -67,15 +67,13 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { with_config( Some(Default::default()), |app, config, _metadata, _cli_options| { - ensure_init(config.project_dir(), MobileTarget::Ios) - .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; + ensure_init(config.project_dir(), MobileTarget::Ios)?; let env = env()?; - init_dot_cargo(app, None).map_err(Error::InitDotCargo)?; + init_dot_cargo(app, None)?; let open = options.open; - run_build(options, config, &env, noise_level) - .map_err(|e| Error::BuildFailed(format!("{:#}", e)))?; + run_build(options, config, &env, noise_level)?; if open { open_and_wait(config, &env); @@ -157,7 +155,7 @@ fn run_build( anyhow::Result::Ok(()) }, ) - .map_err(|e: TargetInvalid| Error::TargetInvalid(e.to_string()))? + .map_err(|e: TargetInvalid| anyhow::anyhow!(e.to_string()))? .map_err(|e: anyhow::Error| e)?; log_finished(out_files, "IPA"); diff --git a/tooling/cli/src/mobile/ios/dev.rs b/tooling/cli/src/mobile/ios/dev.rs index c1e262198..3f8001de1 100644 --- a/tooling/cli/src/mobile/ios/dev.rs +++ b/tooling/cli/src/mobile/ios/dev.rs @@ -1,5 +1,5 @@ use super::{ - device_prompt, ensure_init, env, init_dot_cargo, open_and_wait, with_config, Error, MobileTarget, + device_prompt, ensure_init, env, init_dot_cargo, open_and_wait, with_config, MobileTarget, }; use crate::{ helpers::{config::get as get_tauri_config, flock}, @@ -10,8 +10,9 @@ use crate::{ use clap::Parser; use cargo_mobile::{ - apple::config::Config as AppleConfig, + apple::{config::Config as AppleConfig, device::RunError as DeviceRunError, ios_deploy}, config::app::App, + device::PromptError, env::Env, opts::{NoiseLevel, Profile}, }; @@ -58,12 +59,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { with_config( Some(Default::default()), |app, config, _metadata, _cli_options| { - ensure_init(config.project_dir(), MobileTarget::Ios) - .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; - run_dev(options, app, config, noise_level).map_err(|e| Error::DevFailed(format!("{:#}", e))) + ensure_init(config.project_dir(), MobileTarget::Ios)?; + run_dev(options, app, config, noise_level).map_err(Into::into) }, ) - .map_err(Into::into) } fn run_dev( @@ -76,8 +75,7 @@ fn run_dev( let mut interface = crate::dev::setup(&mut dev_options)?; let bundle_identifier = { - let tauri_config = - get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?; + let tauri_config = get_tauri_config(None)?; let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap(); tauri_config_.tauri.bundle.identifier.clone() @@ -92,7 +90,7 @@ fn run_dev( let _lock = flock::open_rw(&out_dir.join("lock").with_extension("ios"), "iOS")?; let env = env()?; - init_dot_cargo(app, None).map_err(Error::InitDotCargo)?; + init_dot_cargo(app, None)?; let open = options.open; let exit_on_panic = options.exit_on_panic; @@ -124,7 +122,7 @@ fn run_dev( }); Ok(Box::new(c) as Box) } - Err(Error::FailedToPromptForDevice(e)) => { + Err(RunError::FailedToPromptForDevice(e)) => { log::error!("{}", e); open_and_wait(config, &env) } @@ -135,12 +133,19 @@ fn run_dev( ) } +#[derive(Debug, thiserror::Error)] +enum RunError { + #[error(transparent)] + FailedToPromptForDevice(PromptError), + #[error(transparent)] + RunFailed(DeviceRunError), +} fn run( options: MobileOptions, config: &AppleConfig, env: &Env, noise_level: NoiseLevel, -) -> Result { +) -> Result { let profile = if options.debug { Profile::Debug } else { @@ -150,8 +155,8 @@ fn run( let non_interactive = true; // ios-deploy --noninteractive (quit when app crashes or exits) device_prompt(env) - .map_err(Error::FailedToPromptForDevice)? + .map_err(RunError::FailedToPromptForDevice)? .run(config, env, noise_level, non_interactive, profile) .map(DevChild::new) - .map_err(Error::RunFailed) + .map_err(RunError::RunFailed) } diff --git a/tooling/cli/src/mobile/ios/open.rs b/tooling/cli/src/mobile/ios/open.rs index 0304516dd..9d3f52b42 100644 --- a/tooling/cli/src/mobile/ios/open.rs +++ b/tooling/cli/src/mobile/ios/open.rs @@ -1,4 +1,4 @@ -use super::{ensure_init, env, with_config, Error, MobileTarget}; +use super::{ensure_init, env, with_config, MobileTarget}; use crate::Result; use cargo_mobile::os; @@ -6,11 +6,9 @@ pub fn command() -> Result<()> { with_config( Some(Default::default()), |_root_conf, config, _metadata, _cli_options| { - ensure_init(config.project_dir(), MobileTarget::Ios) - .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; + ensure_init(config.project_dir(), MobileTarget::Ios)?; let env = env()?; - os::open_file_with("Xcode", config.project_dir(), &env).map_err(Error::OpenFailed) + os::open_file_with("Xcode", config.project_dir(), &env).map_err(Into::into) }, ) - .map_err(Into::into) } diff --git a/tooling/cli/src/mobile/ios/project.rs b/tooling/cli/src/mobile/ios/project.rs index a0e5a8f35..e1ae7213c 100644 --- a/tooling/cli/src/mobile/ios/project.rs +++ b/tooling/cli/src/mobile/ios/project.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::helpers::template; +use crate::{helpers::template, Result}; +use anyhow::Context; use cargo_mobile::{ apple::{ config::{Config, Metadata}, @@ -23,29 +24,6 @@ use std::{ const TEMPLATE_DIR: Dir<'_> = include_dir!("templates/mobile/ios"); -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error(transparent)] - Rustup(bossy::Error), - #[error(transparent)] - RustVersionCheck(util::RustVersionError), - #[error("failed to install Apple dependencies: {0}")] - DepsInstall(deps::Error), - #[error("failed to process template: {0}")] - TemplateProcessing(String), - #[error("failed to symlink asset directory")] - AssetDirSymlink, - #[error("failed to create directory at {path}: {cause}")] - DirectoryCreation { - path: PathBuf, - cause: std::io::Error, - }, - #[error("failed to run `xcodegen`: {0}")] - Xcodegen(bossy::Error), - #[error("failed to run `pod install`: {0}")] - PodInstall(bossy::Error), -} - // unprefixed app_root seems pretty dangerous!! // TODO: figure out what cargo-mobile meant by that pub fn gen( @@ -56,13 +34,13 @@ pub fn gen( non_interactive: bool, skip_dev_tools: bool, reinstall_deps: bool, -) -> Result<(), Error> { +) -> Result<()> { println!("Installing iOS toolchains..."); - Target::install_all().map_err(Error::Rustup)?; - rust_version_check(wrapper).map_err(Error::RustVersionCheck)?; + Target::install_all()?; + rust_version_check(wrapper)?; deps::install_all(wrapper, non_interactive, skip_dev_tools, reinstall_deps) - .map_err(Error::DepsInstall)?; + .with_context(|| "failed to install Apple dependencies")?; let dest = config.project_dir(); let rel_prefix = util::relativize_path(config.app().root_dir(), &dest); @@ -161,16 +139,18 @@ pub fn gen( File::create(path) }, ) - .map_err(|e| Error::TemplateProcessing(e.to_string()))?; + .with_context(|| "failed to process template")?; ln::force_symlink_relative(config.app().asset_dir(), &dest, ln::TargetStyle::Directory) - .map_err(|_| Error::AssetDirSymlink)?; + .map_err(|_| anyhow::anyhow!("failed to symlink asset directory"))?; // Create all asset catalog directories if they don't already exist for dir in asset_catalogs { - std::fs::create_dir_all(dir).map_err(|cause| Error::DirectoryCreation { - path: dest.clone(), - cause, + std::fs::create_dir_all(dir).map_err(|cause| { + anyhow::anyhow!( + "failed to create directory at {path}: {cause}", + path = dir.display() + ) })?; } @@ -181,13 +161,13 @@ pub fn gen( .with_args(&["generate", "--spec"]) .with_arg(dest.join("project.yml")) .run_and_wait() - .map_err(Error::Xcodegen)?; + .with_context(|| "failed to run `xcodegen`")?; if !ios_pods.is_empty() || !macos_pods.is_empty() { bossy::Command::impure_parse("pod install") .with_arg(format!("--project-directory={}", dest.display())) .run_and_wait() - .map_err(Error::PodInstall)?; + .with_context(|| "failed to run `pod install`")?; } Ok(()) } diff --git a/tooling/cli/src/mobile/ios/xcode_script.rs b/tooling/cli/src/mobile/ios/xcode_script.rs index 4ff2e5bff..870edf52d 100644 --- a/tooling/cli/src/mobile/ios/xcode_script.rs +++ b/tooling/cli/src/mobile/ios/xcode_script.rs @@ -1,4 +1,4 @@ -use super::{env, init_dot_cargo, with_config, Error}; +use super::{env, init_dot_cargo, with_config}; use crate::Result; use clap::Parser; @@ -43,24 +43,24 @@ pub fn command(options: Options) -> Result<()> { with_config(None, |root_conf, config, metadata, cli_options| { let env = env()?; - init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?; + init_dot_cargo(root_conf, None)?; // The `PATH` env var Xcode gives us is missing any additions // made by the user's profile, so we'll manually add cargo's // `PATH`. - let env = env.prepend_to_path( - util::home_dir() - .map_err(Error::NoHomeDir)? - .join(".cargo/bin"), - ); + let env = env.prepend_to_path(util::home_dir()?.join(".cargo/bin")); if !options.sdk_root.is_dir() { - return Err(Error::SdkRootInvalid { - sdk_root: options.sdk_root, - }); + return Err(anyhow::anyhow!( + "SDK root provided by Xcode was invalid. {} doesn't exist or isn't a directory", + options.sdk_root.display(), + )); } let include_dir = options.sdk_root.join("usr/include"); if !include_dir.is_dir() { - return Err(Error::IncludeDirInvalid { include_dir }); + return Err(anyhow::anyhow!( + "Include dir was invalid. {} doesn't exist or isn't a directory", + include_dir.display() + )); } let mut host_env = HashMap::<&str, &OsStr>::new(); @@ -71,7 +71,10 @@ pub fn command(options: Options) -> Result<()> { .sdk_root .join("../../../../MacOSX.platform/Developer/SDKs/MacOSX.sdk"); if !macos_sdk_root.is_dir() { - return Err(Error::MacosSdkRootInvalid { macos_sdk_root }); + return Err(anyhow::anyhow!( + "macOS SDK root was invalid. {0} doesn't exist or isn't a directory", + macos_sdk_root.display() + )); } ( format!("-isysroot {}", macos_sdk_root.display()), @@ -98,7 +101,12 @@ pub fn command(options: Options) -> Result<()> { let triple = match arch.as_str() { "arm64" => "aarch64_apple_ios", "x86_64" => "x86_64_apple_ios", - _ => return Err(Error::ArchInvalid { arch }), + _ => { + return Err(anyhow::anyhow!( + "Arch specified by Xcode was invalid. {} isn't a known arch", + arch + )) + } }; let cflags = format!("CFLAGS_{}", triple); let cxxflags = format!("CFLAGS_{}", triple); @@ -114,21 +122,22 @@ pub fn command(options: Options) -> Result<()> { let target = if macos { &macos_target } else { - Target::for_arch(&arch).ok_or_else(|| Error::ArchInvalid { - arch: arch.to_owned(), + Target::for_arch(&arch).ok_or_else(|| { + anyhow::anyhow!( + "Arch specified by Xcode was invalid. {} isn't a known arch", + arch + ) })? }; - target - .compile_lib( - config, - metadata, - cli_options.noise_level, - true, - profile, - &env, - target_env, - ) - .map_err(Error::CompileLibFailed)?; + target.compile_lib( + config, + metadata, + cli_options.noise_level, + true, + profile, + &env, + target_env, + )?; } Ok(()) })