mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-21 01:32:03 +03:00
refactor(cli): remove mobile Error enum, use anyhow instead (#5076)
This commit is contained in:
parent
0a203a13ae
commit
8cf9af93eb
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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(())
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user