refactor(cli): remove mobile Error enum, use anyhow instead (#5076)

This commit is contained in:
Lucas Fernandes Nogueira 2022-08-28 15:32:50 -03:00 committed by GitHub
parent 0a203a13ae
commit 8cf9af93eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 167 additions and 302 deletions

View File

@ -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<adb::device_list::Error>),
}
#[derive(Parser)]
#[clap(
author,
@ -138,11 +109,10 @@ pub fn get_config(
fn with_config<T>(
cli_options: Option<CliOptions>,
f: impl FnOnce(&App, &AndroidConfig, &AndroidMetadata, CliOptions) -> Result<T, Error>,
) -> Result<T, Error> {
f: impl FnOnce(&App, &AndroidConfig, &AndroidMetadata, CliOptions) -> Result<T>,
) -> Result<T> {
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<T>(
f(&app, &config, &metadata, cli_options)
}
fn env() -> Result<Env, Error> {
let env = super::env().map_err(Error::EnvInitFailed)?;
cargo_mobile::android::env::Env::from_env(env).map_err(Error::AndroidEnvInitFailed)
fn env() -> Result<Env> {
let env = super::env()?;
cargo_mobile::android::env::Env::from_env(env).map_err(Into::into)
}
fn delete_codegen_vars() {

View File

@ -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)
}

View File

@ -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<String>) -> Result<Vec<&'a Target<'a>>, Error> {
fn get_targets_or_all<'a>(targets: Vec<String>) -> Result<Vec<&'a Target<'a>>> {
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<String>) -> Result<Vec<&'a Target<'a>>, 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);
}

View File

@ -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<dyn DevProcess>)
}
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<adb::device_list::Error>),
#[error(transparent)]
RunFailed(DeviceRunError),
}
fn run(
options: MobileOptions,
config: &AndroidConfig,
env: &Env,
metadata: &AndroidMetadata,
noise_level: NoiseLevel,
) -> Result<DevChild, Error> {
) -> Result<DevChild, RunError> {
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)
}

View File

@ -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)
}

View File

@ -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(())
}

View File

@ -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<App, Error> {
let tauri_config =
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
) -> Result<App> {
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
}

View File

@ -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<ios_deploy::DeviceListError>),
#[error(transparent)]
RunFailed(RunError),
#[error("{0}")]
TargetInvalid(String),
}
#[derive(Parser)]
#[clap(
author,
@ -146,11 +108,10 @@ pub fn get_config(
fn with_config<T>(
cli_options: Option<CliOptions>,
f: impl FnOnce(&App, &AppleConfig, &AppleMetadata, CliOptions) -> Result<T, Error>,
) -> Result<T, Error> {
f: impl FnOnce(&App, &AppleConfig, &AppleMetadata, CliOptions) -> Result<T>,
) -> Result<T> {
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));

View File

@ -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");

View File

@ -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<dyn DevProcess>)
}
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<ios_deploy::DeviceListError>),
#[error(transparent)]
RunFailed(DeviceRunError),
}
fn run(
options: MobileOptions,
config: &AppleConfig,
env: &Env,
noise_level: NoiseLevel,
) -> Result<DevChild, Error> {
) -> Result<DevChild, RunError> {
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)
}

View File

@ -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)
}

View File

@ -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(())
}

View File

@ -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(())
})