fix(cli): set current dir to tauri dir before reading config, closes #6771 (#6782)

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
fix(cli): set current dir to tauri dir before reading config, closes #6771
This commit is contained in:
Amr Bashir
2023-05-26 19:45:20 +03:00
committed by GitHub
parent 735db1ce83
commit 1ed2600da6
18 changed files with 456 additions and 388 deletions

View File

@@ -0,0 +1,6 @@
---
'cli.rs': 'patch'
'cli.js': 'patch'
---
Set current directory to tauri directory before reading config file.

View File

@@ -7,6 +7,7 @@ use crate::{
app_paths::{app_dir, tauri_dir},
command_env,
config::{get as get_config, AppUrl, HookCommand, WindowUrl, MERGE_CONFIG_EXTENSION_NAME},
resolve_merge_config,
updater_signature::{read_key_from_file, secret_key as updater_secret_key, sign_file},
},
interface::{AppInterface, AppSettings, Interface},
@@ -233,22 +234,14 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
}
pub fn setup(options: &mut Options, mobile: bool) -> Result<AppInterface> {
let (merge_config, merge_config_path) = match &options.config {
Some(config) if config.starts_with('{') => (Some(config.to_string()), None),
Some(config) => (
Some(std::fs::read_to_string(config).with_context(|| "failed to read custom configuration")?),
Some(config.clone()),
),
None => (None, None),
};
let (merge_config, merge_config_path) = resolve_merge_config(&options.config)?;
options.config = merge_config;
let config = get_config(options.config.as_deref())?;
let tauri_path = tauri_dir();
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
let config = get_config(options.config.as_deref())?;
let config_guard = config.lock().unwrap();
let config_ = config_guard.as_ref().unwrap();

View File

@@ -7,6 +7,7 @@ use crate::{
app_paths::{app_dir, tauri_dir},
command_env,
config::{get as get_config, reload as reload_config, AppUrl, BeforeDevCommand, WindowUrl},
resolve_merge_config,
},
interface::{AppInterface, DevProcess, ExitReason, Interface},
CommandExt, Result,
@@ -137,21 +138,14 @@ pub fn local_ip_address(force: bool) -> &'static IpAddr {
}
pub fn setup(options: &mut Options, mobile: bool) -> Result<AppInterface> {
let tauri_path = tauri_dir();
options.config = if let Some(config) = &options.config {
Some(if config.starts_with('{') {
config.to_string()
} else {
std::fs::read_to_string(config).with_context(|| "failed to read custom configuration")?
})
} else {
None
};
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
let (merge_config, _merge_config_path) = resolve_merge_config(&options.config)?;
options.config = merge_config;
let config = get_config(options.config.as_deref())?;
let tauri_path = tauri_dir();
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
let interface = AppInterface::new(
config.lock().unwrap().as_ref().unwrap(),
options.target.clone(),

View File

@@ -12,7 +12,7 @@ pub use tauri_utils::config::*;
use std::{
collections::HashMap,
env::{set_var, var_os},
env::{current_dir, set_current_dir, set_var, var_os},
ffi::OsStr,
process::exit,
sync::{Arc, Mutex},
@@ -165,7 +165,13 @@ fn get_internal(merge_config: Option<&str>, reload: bool) -> crate::Result<Confi
}
}
// the `Config` deserializer for `package > version` can resolve the version from a path relative to the config path
// so we actually need to change the current working directory here
let current_dir = current_dir()?;
set_current_dir(config_path.parent().unwrap())?;
let config: Config = serde_json::from_value(config)?;
// revert to previous working directory
set_current_dir(current_dir)?;
*config_handle().lock().unwrap() = Some(ConfigMetadata {
inner: config,

View File

@@ -11,6 +11,8 @@ pub mod template;
pub mod updater_signature;
pub mod web_dev_server;
use anyhow::Context;
use std::{
collections::HashMap,
path::{Path, PathBuf},
@@ -52,3 +54,16 @@ pub fn cross_command(bin: &str) -> Command {
let cmd = Command::new(bin);
cmd
}
pub fn resolve_merge_config(
config: &Option<String>,
) -> crate::Result<(Option<String>, Option<String>)> {
match config {
Some(config) if config.starts_with('{') => Ok((Some(config.to_string()), None)),
Some(config) => Ok((
Some(std::fs::read_to_string(config).with_context(|| "failed to read custom configuration")?),
Some(config.clone()),
)),
None => Ok((None, None)),
}
}

View File

@@ -2,7 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::{helpers::app_paths::tauri_dir, Result};
use crate::{
helpers::{app_paths::tauri_dir, config::get as get_tauri_config},
Result,
};
use std::{
collections::HashMap,
@@ -356,24 +359,31 @@ fn png(source: &DynamicImage, out_dir: &Path, ios_color: Rgba<u8>) -> Result<()>
}
let mut entries = desktop_entries(out_dir);
let _ = crate::mobile::android::with_config(
Some(Default::default()),
|_app, config, _metadata, _cli_options| {
let android_out = out_dir.parent().unwrap().join(format!(
"gen/android/{}/app/src/main/res/",
config.app().name_snake()
));
let out = if android_out.exists() {
android_out
} else {
let out = out_dir.join("android");
create_dir_all(&out).context("Can't create Android output directory")?;
out
};
entries.extend(android_entries(&out)?);
Ok(())
},
);
// Android
let (config, _metadata) = {
let tauri_config = get_tauri_config(None)?;
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
crate::mobile::android::get_config(
&crate::mobile::get_app(tauri_config_),
tauri_config_,
&Default::default(),
)
};
let android_out = out_dir.parent().unwrap().join(format!(
"gen/android/{}/app/src/main/res/",
config.app().name_snake()
));
let out = if android_out.exists() {
android_out
} else {
let out = out_dir.join("android");
create_dir_all(&out).context("Can't create Android output directory")?;
out
};
entries.extend(android_entries(&out)?);
let ios_out = out_dir
.parent()

View File

@@ -32,10 +32,7 @@ use super::{
log_finished, read_options, setup_dev_config, CliOptions, Target as MobileTarget,
MIN_DEVICE_MATCH_SCORE,
};
use crate::{
helpers::config::{get as get_tauri_config, Config as TauriConfig},
Result,
};
use crate::{helpers::config::Config as TauriConfig, Result};
mod android_studio_script;
mod build;
@@ -97,11 +94,10 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> {
}
pub fn get_config(
app: Option<App>,
app: &App,
config: &TauriConfig,
cli_options: &CliOptions,
) -> (App, AndroidConfig, AndroidMetadata) {
let app = app.unwrap_or_else(|| get_app(config));
) -> (AndroidConfig, AndroidMetadata) {
let android_options = cli_options.clone();
let raw = RawAndroidConfig {
@@ -158,23 +154,7 @@ pub fn get_config(
src_main_dir.join("generated"),
);
(app, config, metadata)
}
pub fn with_config<T>(
cli_options: Option<CliOptions>,
f: impl FnOnce(&App, &AndroidConfig, &AndroidMetadata, CliOptions) -> Result<T>,
) -> Result<T> {
let (app, config, metadata, cli_options) = {
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_.tauri.bundle.identifier));
let (app, config, metadata) = get_config(None, tauri_config_, &cli_options);
(app, config, metadata, cli_options)
};
f(&app, &config, &metadata, cli_options)
(config, metadata)
}
fn env() -> Result<Env> {

View File

@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use super::{detect_target_ok, ensure_init, env, with_config, MobileTarget};
use crate::Result;
use super::{detect_target_ok, ensure_init, env, get_app, get_config, read_options, MobileTarget};
use crate::{helpers::config::get as get_tauri_config, Result};
use clap::{ArgAction, Parser};
use tauri_mobile::{
@@ -36,28 +36,35 @@ pub fn command(options: Options) -> Result<()> {
Profile::Debug
};
with_config(None, |_app, config, metadata, cli_options| {
ensure_init(config.project_dir(), MobileTarget::Android)?;
let tauri_config = get_tauri_config(None)?;
let env = env()?;
let (config, metadata, cli_options) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let cli_options = read_options(&tauri_config_.tauri.bundle.identifier);
let (config, metadata) = get_config(&get_app(tauri_config_), tauri_config_, &cli_options);
(config, metadata, cli_options)
};
ensure_init(config.project_dir(), MobileTarget::Android)?;
call_for_targets_with_fallback(
options.targets.unwrap_or_default().iter(),
&detect_target_ok,
&env,
|target: &Target| {
target
.build(
config,
metadata,
&env,
cli_options.noise_level,
true,
profile,
)
.map_err(Into::into)
},
)
.map_err(|e| anyhow::anyhow!(e.to_string()))?
})
let env = env()?;
call_for_targets_with_fallback(
options.targets.unwrap_or_default().iter(),
&detect_target_ok,
&env,
|target: &Target| {
target
.build(
&config,
&metadata,
&env,
cli_options.noise_level,
true,
profile,
)
.map_err(Into::into)
},
)
.map_err(|e| anyhow::anyhow!(e.to_string()))?
}

View File

@@ -3,25 +3,30 @@
// SPDX-License-Identifier: MIT
use super::{
configure_cargo, delete_codegen_vars, ensure_init, env, inject_assets, log_finished,
open_and_wait, with_config, MobileTarget,
configure_cargo, delete_codegen_vars, ensure_init, env, get_app, get_config, inject_assets,
log_finished, open_and_wait, MobileTarget,
};
use crate::{
build::Options as BuildOptions,
helpers::{config::get as get_config, flock},
helpers::{
app_paths::tauri_dir,
config::{get as get_tauri_config, ConfigHandle},
flock, resolve_merge_config,
},
interface::{AppSettings, Interface, Options as InterfaceOptions},
mobile::{write_options, CliOptions},
Result,
};
use clap::{ArgAction, Parser};
use anyhow::Context;
use tauri_mobile::{
android::{aab, apk, config::Config as AndroidConfig, env::Env, target::Target},
opts::{NoiseLevel, Profile},
target::TargetTrait,
};
use std::env::set_var;
use std::env::{set_current_dir, set_var};
#[derive(Debug, Clone, Parser)]
#[clap(about = "Android build")]
@@ -73,54 +78,72 @@ impl From<Options> for BuildOptions {
}
}
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
pub fn command(mut options: Options, noise_level: NoiseLevel) -> Result<()> {
delete_codegen_vars();
with_config(
Some(Default::default()),
|app, config, metadata, _cli_options| {
set_var("WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION", "");
set_var("WRY_RUSTWEBVIEW_CLASS_INIT", "");
let profile = if options.debug {
Profile::Debug
} else {
Profile::Release
};
let (merge_config, _merge_config_path) = resolve_merge_config(&options.config)?;
options.config = merge_config;
ensure_init(config.project_dir(), MobileTarget::Android)?;
let tauri_config = get_tauri_config(options.config.as_deref())?;
let (app, config, metadata) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let app = get_app(tauri_config_);
let (config, metadata) = get_config(&app, tauri_config_, &Default::default());
(app, config, metadata)
};
let mut env = env()?;
configure_cargo(app, Some((&mut env, config)))?;
set_var("WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION", "");
set_var("WRY_RUSTWEBVIEW_CLASS_INIT", "");
// run an initial build to initialize plugins
Target::all().values().next().unwrap().build(
config,
metadata,
&env,
noise_level,
true,
if options.debug {
Profile::Debug
} else {
Profile::Release
},
)?;
let profile = if options.debug {
Profile::Debug
} else {
Profile::Release
};
let open = options.open;
run_build(options, profile, config, &mut env, noise_level)?;
let tauri_path = tauri_dir();
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
if open {
open_and_wait(config, &env);
}
ensure_init(config.project_dir(), MobileTarget::Android)?;
Ok(())
let mut env = env()?;
configure_cargo(&app, Some((&mut env, &config)))?;
// run an initial build to initialize plugins
Target::all().values().next().unwrap().build(
&config,
&metadata,
&env,
noise_level,
true,
if options.debug {
Profile::Debug
} else {
Profile::Release
},
)
.map_err(Into::into)
)?;
let open = options.open;
run_build(
options,
tauri_config,
profile,
&config,
&mut env,
noise_level,
)?;
if open {
open_and_wait(&config, &env);
}
Ok(())
}
fn run_build(
mut options: Options,
tauri_config: ConfigHandle,
profile: Profile,
config: &AndroidConfig,
env: &mut Env,
@@ -153,8 +176,6 @@ fn run_build(
let out_dir = bin_path.parent().unwrap();
let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?;
let tauri_config = get_config(options.config.as_deref())?;
let cli_options = CliOptions {
features: build_options.features.clone(),
args: build_options.args.clone(),

View File

@@ -3,18 +3,23 @@
// SPDX-License-Identifier: MIT
use super::{
configure_cargo, delete_codegen_vars, device_prompt, ensure_init, env, inject_assets,
open_and_wait, setup_dev_config, with_config, MobileTarget,
configure_cargo, delete_codegen_vars, device_prompt, ensure_init, env, get_app, get_config,
inject_assets, open_and_wait, setup_dev_config, MobileTarget,
};
use crate::{
dev::Options as DevOptions,
helpers::{config::get as get_config, flock},
helpers::{
app_paths::tauri_dir,
config::{get as get_tauri_config, ConfigHandle},
flock, resolve_merge_config,
},
interface::{AppSettings, Interface, MobileOptions, Options as InterfaceOptions},
mobile::{write_options, CliOptions, DevChild, DevProcess},
Result,
};
use clap::{ArgAction, Parser};
use anyhow::Context;
use tauri_mobile::{
android::{
config::{Config as AndroidConfig, Metadata as AndroidMetadata},
@@ -27,7 +32,7 @@ use tauri_mobile::{
target::TargetTrait,
};
use std::env::set_var;
use std::env::{set_current_dir, set_var};
const WEBVIEW_CLIENT_CLASS_EXTENSION: &str = "
@android.annotation.SuppressLint(\"WebViewClientOnReceivedSslError\")
@@ -91,25 +96,38 @@ impl From<Options> for DevOptions {
}
}
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
pub fn command(mut options: Options, noise_level: NoiseLevel) -> Result<()> {
delete_codegen_vars();
with_config(
Some(Default::default()),
|app, config, metadata, _cli_options| {
set_var(
"WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION",
WEBVIEW_CLIENT_CLASS_EXTENSION,
);
set_var("WRY_RUSTWEBVIEW_CLASS_INIT", WEBVIEW_CLASS_INIT);
ensure_init(config.project_dir(), MobileTarget::Android)?;
run_dev(options, app, config, metadata, noise_level).map_err(Into::into)
},
)
.map_err(Into::into)
let (merge_config, _merge_config_path) = resolve_merge_config(&options.config)?;
options.config = merge_config;
let tauri_config = get_tauri_config(options.config.as_deref())?;
let (app, config, metadata) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let app = get_app(tauri_config_);
let (config, metadata) = get_config(&app, tauri_config_, &Default::default());
(app, config, metadata)
};
set_var(
"WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION",
WEBVIEW_CLIENT_CLASS_EXTENSION,
);
set_var("WRY_RUSTWEBVIEW_CLASS_INIT", WEBVIEW_CLASS_INIT);
let tauri_path = tauri_dir();
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
ensure_init(config.project_dir(), MobileTarget::Android)?;
run_dev(options, tauri_config, &app, &config, &metadata, noise_level)
}
fn run_dev(
mut options: Options,
tauri_config: ConfigHandle,
app: &App,
config: &AndroidConfig,
metadata: &AndroidMetadata,
@@ -187,7 +205,6 @@ fn run_dev(
vars: Default::default(),
};
let tauri_config = get_config(options.config.as_deref())?;
let _handle = write_options(
&tauri_config
.lock()

View File

@@ -2,18 +2,21 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use super::{ensure_init, env, inject_assets, with_config, MobileTarget};
use crate::{helpers::config::get as get_config, Result};
use super::{ensure_init, env, get_app, get_config, inject_assets, MobileTarget};
use crate::{helpers::config::get as get_tauri_config, Result};
use tauri_mobile::os;
pub fn command() -> Result<()> {
with_config(
Some(Default::default()),
|_root_conf, config, _metadata, _cli_options| {
ensure_init(config.project_dir(), MobileTarget::Android)?;
inject_assets(config, get_config(None)?.lock().unwrap().as_ref().unwrap())?;
let env = env()?;
os::open_file_with("Android Studio", config.project_dir(), &env.base).map_err(Into::into)
},
)
let tauri_config = get_tauri_config(None)?;
let (config, _metadata) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
get_config(&get_app(tauri_config_), tauri_config_, &Default::default())
};
ensure_init(config.project_dir(), MobileTarget::Android)?;
inject_assets(&config, tauri_config.lock().unwrap().as_ref().unwrap())?;
let env = env()?;
os::open_file_with("Android Studio", config.project_dir(), &env.base).map_err(Into::into)
}

View File

@@ -31,6 +31,7 @@ pub fn command(
skip_targets_install: bool,
) -> Result<()> {
let wrapper = TextWrapper::with_splitter(textwrap::termwidth(), textwrap::NoHyphenation);
exec(
target,
&wrapper,
@@ -86,7 +87,9 @@ pub fn exec(
#[allow(unused_variables)] reinstall_deps: bool,
skip_targets_install: bool,
) -> Result<App> {
let current_dir = current_dir()?;
let tauri_config = get_tauri_config(None)?;
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
@@ -100,10 +103,8 @@ pub fn exec(
.map(|bin| {
let path = PathBuf::from(&bin);
if path.exists() {
if let Ok(dir) = current_dir() {
let absolute_path = util::prefix_path(dir, path);
return absolute_path.into();
}
let absolute_path = util::prefix_path(&current_dir, path);
return absolute_path.into();
}
bin
})
@@ -112,11 +113,9 @@ pub fn exec(
for arg in args {
let path = PathBuf::from(&arg);
if path.exists() {
if let Ok(dir) = current_dir() {
let absolute_path = util::prefix_path(dir, path);
build_args.push(absolute_path.to_string_lossy().into_owned());
continue;
}
let absolute_path = util::prefix_path(&current_dir, path);
build_args.push(absolute_path.to_string_lossy().into_owned());
continue;
}
build_args.push(arg.to_string_lossy().into_owned());
if arg == "android" || arg == "ios" {
@@ -158,8 +157,9 @@ pub fn exec(
// Generate Android Studio project
Target::Android => match AndroidEnv::new() {
Ok(_env) => {
let (app, config, metadata) =
super::android::get_config(Some(app), tauri_config_, &Default::default());
let app = get_app(tauri_config_);
let (config, metadata) =
super::android::get_config(&app, tauri_config_, &Default::default());
map.insert("android", &config);
super::android::project::gen(
&config,
@@ -186,8 +186,7 @@ pub fn exec(
#[cfg(target_os = "macos")]
// Generate Xcode project
Target::Ios => {
let (app, config, metadata) =
super::ios::get_config(Some(app), tauri_config_, &Default::default());
let (config, metadata) = super::ios::get_config(&app, tauri_config_, &Default::default());
map.insert("apple", &config);
super::ios::project::gen(
&config,

View File

@@ -28,10 +28,7 @@ use super::{
log_finished, read_options, setup_dev_config, CliOptions, Target as MobileTarget,
MIN_DEVICE_MATCH_SCORE,
};
use crate::{
helpers::config::{get as get_tauri_config, Config as TauriConfig},
Result,
};
use crate::{helpers::config::Config as TauriConfig, Result};
use std::{process::exit, thread::sleep, time::Duration};
@@ -101,11 +98,10 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> {
}
pub fn get_config(
app: Option<App>,
app: &App,
config: &TauriConfig,
cli_options: &CliOptions,
) -> (App, AppleConfig, AppleMetadata) {
let app = app.unwrap_or_else(|| get_app(config));
) -> (AppleConfig, AppleMetadata) {
let ios_options = cli_options.clone();
let raw = RawAppleConfig {
@@ -144,23 +140,7 @@ pub fn get_config(
macos: Default::default(),
};
(app, config, metadata)
}
fn with_config<T>(
cli_options: Option<CliOptions>,
f: impl FnOnce(&App, &AppleConfig, &AppleMetadata, CliOptions) -> Result<T>,
) -> Result<T> {
let (app, config, metadata, cli_options) = {
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_.tauri.bundle.identifier));
let (app, config, metadata) = get_config(None, tauri_config_, &cli_options);
(app, config, metadata, cli_options)
};
f(&app, &config, &metadata, cli_options)
(config, metadata)
}
fn ios_deploy_device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result<Device<'a>> {

View File

@@ -3,18 +3,23 @@
// SPDX-License-Identifier: MIT
use super::{
configure_cargo, detect_target_ok, ensure_init, env, log_finished, open_and_wait, with_config,
MobileTarget,
configure_cargo, detect_target_ok, ensure_init, env, get_app, get_config, log_finished,
open_and_wait, MobileTarget,
};
use crate::{
build::Options as BuildOptions,
helpers::{config::get as get_config, flock},
helpers::{
app_paths::tauri_dir,
config::{get as get_tauri_config, ConfigHandle},
flock, resolve_merge_config,
},
interface::{AppSettings, Interface, Options as InterfaceOptions},
mobile::{write_options, CliOptions},
Result,
};
use clap::{ArgAction, Parser};
use anyhow::Context;
use tauri_mobile::{
apple::{config::Config as AppleConfig, target::Target},
env::Env,
@@ -22,7 +27,7 @@ use tauri_mobile::{
target::{call_for_targets_with_fallback, TargetInvalid, TargetTrait},
};
use std::fs;
use std::{env::set_current_dir, fs};
#[derive(Debug, Clone, Parser)]
#[clap(about = "iOS build")]
@@ -69,30 +74,40 @@ impl From<Options> for BuildOptions {
}
}
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)?;
pub fn command(mut options: Options, noise_level: NoiseLevel) -> Result<()> {
let (merge_config, _merge_config_path) = resolve_merge_config(&options.config)?;
options.config = merge_config;
let mut env = env()?;
configure_cargo(app, None)?;
let tauri_config = get_tauri_config(options.config.as_deref())?;
let (app, config) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let app = get_app(tauri_config_);
let (config, _metadata) = get_config(&app, tauri_config_, &Default::default());
(app, config)
};
let open = options.open;
run_build(options, config, &mut env, noise_level)?;
let tauri_path = tauri_dir();
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
if open {
open_and_wait(config, &env);
}
ensure_init(config.project_dir(), MobileTarget::Ios)?;
Ok(())
},
)
.map_err(Into::into)
let mut env = env()?;
configure_cargo(&app, None)?;
let open = options.open;
run_build(options, tauri_config, &config, &mut env, noise_level)?;
if open {
open_and_wait(&config, &env);
}
Ok(())
}
fn run_build(
mut options: Options,
tauri_config: ConfigHandle,
config: &AppleConfig,
env: &mut Env,
noise_level: NoiseLevel,
@@ -129,7 +144,7 @@ fn run_build(
vars: Default::default(),
};
let _handle = write_options(
&get_config(options.config.as_deref())?
&tauri_config
.lock()
.unwrap()
.as_ref()

View File

@@ -3,18 +3,23 @@
// SPDX-License-Identifier: MIT
use super::{
configure_cargo, device_prompt, ensure_init, env, open_and_wait, setup_dev_config, with_config,
MobileTarget, APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME,
configure_cargo, device_prompt, ensure_init, env, get_app, get_config, open_and_wait,
setup_dev_config, MobileTarget, APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME,
};
use crate::{
dev::Options as DevOptions,
helpers::{config::get as get_config, flock},
helpers::{
app_paths::tauri_dir,
config::{get as get_tauri_config, ConfigHandle},
flock, resolve_merge_config,
},
interface::{AppSettings, Interface, MobileOptions, Options as InterfaceOptions},
mobile::{write_options, CliOptions, DevChild, DevProcess},
Result,
};
use clap::{ArgAction, Parser};
use anyhow::Context;
use dialoguer::{theme::ColorfulTheme, Select};
use tauri_mobile::{
apple::{config::Config as AppleConfig, device::Device, teams::find_development_teams},
@@ -23,7 +28,7 @@ use tauri_mobile::{
opts::{NoiseLevel, Profile},
};
use std::env::{set_var, var_os};
use std::env::{set_current_dir, set_var, var_os};
#[derive(Debug, Clone, Parser)]
#[clap(about = "iOS dev")]
@@ -78,7 +83,7 @@ impl From<Options> for DevOptions {
}
}
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
pub fn command(mut options: Options, noise_level: NoiseLevel) -> Result<()> {
if var_os(APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME).is_none() {
if let Ok(teams) = find_development_teams() {
let index = match teams.len() {
@@ -109,17 +114,29 @@ 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)?;
run_dev(options, app, config, noise_level).map_err(Into::into)
},
)
let (merge_config, _merge_config_path) = resolve_merge_config(&options.config)?;
options.config = merge_config;
let tauri_config = get_tauri_config(options.config.as_deref())?;
let (app, config) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let app = get_app(tauri_config_);
let (config, _metadata) = get_config(&app, tauri_config_, &Default::default());
(app, config)
};
let tauri_path = tauri_dir();
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
ensure_init(config.project_dir(), MobileTarget::Ios)?;
run_dev(options, tauri_config, &app, &config, noise_level)
}
fn run_dev(
mut options: Options,
tauri_config: ConfigHandle,
app: &App,
config: &AppleConfig,
noise_level: NoiseLevel,
@@ -177,7 +194,7 @@ fn run_dev(
vars: Default::default(),
};
let _handle = write_options(
&get_config(options.config.as_deref())?
&tauri_config
.lock()
.unwrap()
.as_ref()

View File

@@ -2,17 +2,22 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use super::{ensure_init, env, with_config, MobileTarget};
use crate::Result;
use super::{ensure_init, env, get_app, get_config, MobileTarget};
use crate::{helpers::config::get as get_tauri_config, Result};
use anyhow::Context;
use tauri_mobile::os;
pub fn command() -> Result<()> {
with_config(
Some(Default::default()),
|_root_conf, config, _metadata, _cli_options| {
ensure_init(config.project_dir(), MobileTarget::Ios)?;
let env = env()?;
os::open_file_with("Xcode", config.project_dir(), &env).map_err(Into::into)
},
)
let tauri_config = get_tauri_config(None)?;
let (config, _metadata) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
get_config(&get_app(tauri_config_), tauri_config_, &Default::default())
};
ensure_init(config.project_dir(), MobileTarget::Ios)?;
let env = env()?;
os::open_file_with("Xcode", config.project_dir(), &env).map_err(Into::into)
}

View File

@@ -2,17 +2,23 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use super::{env, with_config};
use super::{env, get_app, get_config, read_options};
use crate::{
helpers::config::get as get_config,
helpers::config::get as get_tauri_config,
interface::{AppInterface, AppSettings, Interface, Options as InterfaceOptions},
Result,
};
use anyhow::Context;
use clap::Parser;
use tauri_mobile::{apple::target::Target, opts::Profile};
use std::{collections::HashMap, env::var_os, ffi::OsStr, path::PathBuf};
use std::{
collections::HashMap,
env::{current_dir, set_current_dir, var_os},
ffi::OsStr,
path::PathBuf,
};
#[derive(Debug, Parser)]
pub struct Options {
@@ -57,165 +63,159 @@ pub fn command(options: Options) -> Result<()> {
// `xcode-script` is ran from the `gen/apple` folder when not using NPM.
if var_os("npm_lifecycle_event").is_none() {
std::env::set_current_dir(
std::env::current_dir()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap(),
)
.unwrap();
set_current_dir(current_dir()?.parent().unwrap().parent().unwrap()).unwrap();
}
let profile = profile_from_configuration(&options.configuration);
let macos = macos_from_platform(&options.platform);
with_config(None, |_root_conf, config, metadata, cli_options| {
let env = env()?.explicit_env_vars(cli_options.vars);
let tauri_config = get_tauri_config(None)?;
if !options.sdk_root.is_dir() {
let (config, metadata, cli_options) = {
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let cli_options = read_options(&tauri_config_.tauri.bundle.identifier);
let (config, metadata) = get_config(&get_app(tauri_config_), tauri_config_, &cli_options);
(config, metadata, cli_options)
};
let env = env()?.explicit_env_vars(cli_options.vars);
if !options.sdk_root.is_dir() {
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(anyhow::anyhow!(
"Include dir was invalid. {} doesn't exist or isn't a directory",
include_dir.display()
));
}
// Host flags that are used by build scripts
let macos_isysroot = {
let macos_sdk_root = options
.sdk_root
.join("../../../../MacOSX.platform/Developer/SDKs/MacOSX.sdk");
if !macos_sdk_root.is_dir() {
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(anyhow::anyhow!(
"Include dir was invalid. {} doesn't exist or isn't a directory",
include_dir.display()
"Invalid SDK root {}",
macos_sdk_root.display()
));
}
format!("-isysroot {}", macos_sdk_root.display())
};
// Host flags that are used by build scripts
let macos_isysroot = {
let macos_sdk_root = options
.sdk_root
.join("../../../../MacOSX.platform/Developer/SDKs/MacOSX.sdk");
if !macos_sdk_root.is_dir() {
return Err(anyhow::anyhow!(
"Invalid SDK root {}",
macos_sdk_root.display()
));
}
format!("-isysroot {}", macos_sdk_root.display())
};
let mut host_env = HashMap::<&str, &OsStr>::new();
let mut host_env = HashMap::<&str, &OsStr>::new();
host_env.insert("RUST_BACKTRACE", "1".as_ref());
host_env.insert("RUST_BACKTRACE", "1".as_ref());
host_env.insert("CFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
host_env.insert("CXXFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
host_env.insert("CFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
host_env.insert("CXXFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref());
host_env.insert(
"OBJC_INCLUDE_PATH_x86_64_apple_darwin",
include_dir.as_os_str(),
);
host_env.insert(
"OBJC_INCLUDE_PATH_x86_64_apple_darwin",
include_dir.as_os_str(),
);
host_env.insert(
"FRAMEWORK_SEARCH_PATHS",
options.framework_search_paths.as_ref(),
);
host_env.insert(
"GCC_PREPROCESSOR_DEFINITIONS",
options.gcc_preprocessor_definitions.as_ref(),
);
host_env.insert("HEADER_SEARCH_PATHS", options.header_search_paths.as_ref());
host_env.insert(
"FRAMEWORK_SEARCH_PATHS",
options.framework_search_paths.as_ref(),
);
host_env.insert(
"GCC_PREPROCESSOR_DEFINITIONS",
options.gcc_preprocessor_definitions.as_ref(),
);
host_env.insert("HEADER_SEARCH_PATHS", options.header_search_paths.as_ref());
let macos_target = Target::macos();
let macos_target = Target::macos();
let isysroot = format!("-isysroot {}", options.sdk_root.display());
let isysroot = format!("-isysroot {}", options.sdk_root.display());
let tauri_config = get_config(None)?;
// when using Xcode, the arches will be ['Simulator', 'arm64'] instead of ['arm64-sim']
let arches = if options.arches.contains(&"Simulator".into()) {
vec![if cfg!(target_arch = "aarch64") {
"arm64-sim".to_string()
} else {
"x86_64".to_string()
}]
// when using Xcode, the arches will be ['Simulator', 'arm64'] instead of ['arm64-sim']
let arches = if options.arches.contains(&"Simulator".into()) {
vec![if cfg!(target_arch = "aarch64") {
"arm64-sim".to_string()
} else {
options.arches
};
for arch in arches {
// Set target-specific flags
let (env_triple, rust_triple) = match arch.as_str() {
"arm64" => ("aarch64_apple_ios", "aarch64-apple-ios"),
"arm64-sim" => ("aarch64_apple_ios_sim", "aarch64-apple-ios-sim"),
"x86_64" => ("x86_64_apple_ios", "x86_64-apple-ios"),
_ => {
return Err(anyhow::anyhow!(
"Arch specified by Xcode was invalid. {} isn't a known arch",
arch
))
}
};
let interface = AppInterface::new(
tauri_config.lock().unwrap().as_ref().unwrap(),
Some(rust_triple.into()),
)?;
let cflags = format!("CFLAGS_{}", env_triple);
let cxxflags = format!("CFLAGS_{}", env_triple);
let objc_include_path = format!("OBJC_INCLUDE_PATH_{}", env_triple);
let mut target_env = host_env.clone();
target_env.insert(cflags.as_ref(), isysroot.as_ref());
target_env.insert(cxxflags.as_ref(), isysroot.as_ref());
target_env.insert(objc_include_path.as_ref(), include_dir.as_ref());
let target = if macos {
&macos_target
} else {
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,
)?;
let bin_path = interface
.app_settings()
.app_binary_path(&InterfaceOptions {
debug: matches!(profile, Profile::Debug),
target: Some(rust_triple.into()),
..Default::default()
})?;
let out_dir = bin_path.parent().unwrap();
let lib_path = out_dir.join(format!("lib{}.a", config.app().lib_name()));
if !lib_path.exists() {
return Err(anyhow::anyhow!("Library not found at {}. Make sure your Cargo.toml file has a [lib] block with `crate-type = [\"staticlib\", \"cdylib\", \"rlib\"]`", lib_path.display()));
}
let project_dir = config.project_dir();
std::fs::create_dir_all(project_dir.join(format!(
"Externals/{}",
profile.as_str()
)))?;
std::fs::copy(
lib_path,
project_dir.join(format!(
"Externals/{}/lib{}.a",
profile.as_str(),
config.app().lib_name()
"x86_64".to_string()
}]
} else {
options.arches
};
for arch in arches {
// Set target-specific flags
let (env_triple, rust_triple) = match arch.as_str() {
"arm64" => ("aarch64_apple_ios", "aarch64-apple-ios"),
"arm64-sim" => ("aarch64_apple_ios_sim", "aarch64-apple-ios-sim"),
"x86_64" => ("x86_64_apple_ios", "x86_64-apple-ios"),
_ => {
return Err(anyhow::anyhow!(
"Arch specified by Xcode was invalid. {} isn't a known arch",
arch
))
)?;
}
};
let interface = AppInterface::new(
tauri_config.lock().unwrap().as_ref().unwrap(),
Some(rust_triple.into()),
)?;
let cflags = format!("CFLAGS_{}", env_triple);
let cxxflags = format!("CFLAGS_{}", env_triple);
let objc_include_path = format!("OBJC_INCLUDE_PATH_{}", env_triple);
let mut target_env = host_env.clone();
target_env.insert(cflags.as_ref(), isysroot.as_ref());
target_env.insert(cxxflags.as_ref(), isysroot.as_ref());
target_env.insert(objc_include_path.as_ref(), include_dir.as_ref());
let target = if macos {
&macos_target
} else {
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,
)?;
let bin_path = interface
.app_settings()
.app_binary_path(&InterfaceOptions {
debug: matches!(profile, Profile::Debug),
target: Some(rust_triple.into()),
..Default::default()
})?;
let out_dir = bin_path.parent().unwrap();
let lib_path = out_dir.join(format!("lib{}.a", config.app().lib_name()));
if !lib_path.exists() {
return Err(anyhow::anyhow!("Library not found at {}. Make sure your Cargo.toml file has a [lib] block with `crate-type = [\"staticlib\", \"cdylib\", \"rlib\"]`", lib_path.display()));
}
Ok(())
})
.map_err(Into::into)
let project_dir = config.project_dir();
std::fs::create_dir_all(project_dir.join(format!("Externals/{}", profile.as_str())))?;
std::fs::copy(
lib_path,
project_dir.join(format!(
"Externals/{}/lib{}.a",
profile.as_str(),
config.app().lib_name()
)),
)?;
}
Ok(())
}

View File

@@ -262,7 +262,7 @@ fn read_options(identifier: &str) -> CliOptions {
options
}
fn get_app(config: &TauriConfig) -> App {
pub fn get_app(config: &TauriConfig) -> App {
let mut s = config.tauri.bundle.identifier.rsplit('.');
let app_name = s.next().unwrap_or("app").to_string();
let mut domain = String::new();