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