refactor tauri-cli (#14836)

* refactor(tauri-cli): use OsString where possible

* refactor(tauri-cli): remove needless scoping blocks

* refactor(tauri-cli): make return type concrete

* refactor(tauri-cli): use ?

* refactor(tauri-cli): coerce later to trait object

* refactor(tauri-cli): remove clone

* refactor(tauri-cli): make better use of static OnceLock

* fix(tauri-cli): upgrade atomics to SeqCst

* Add change file

* Update .changes/change-pr-14836.md

Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com>
This commit is contained in:
sftse
2026-01-29 03:39:00 +01:00
committed by GitHub
parent d453e2e06a
commit e3fdcb5002
11 changed files with 106 additions and 131 deletions

View File

@@ -0,0 +1,6 @@
---
"@tauri-apps/cli": patch:changes
"tauri-cli": patch:changes
---
Continued refactors of tauri-cli, fix too weak atomics.

View File

@@ -25,13 +25,13 @@ use std::{
process::{exit, Command, Stdio},
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex, OnceLock,
OnceLock,
},
};
mod builtin_dev_server;
static BEFORE_DEV: OnceLock<Mutex<Arc<SharedChild>>> = OnceLock::new();
static BEFORE_DEV: OnceLock<SharedChild> = OnceLock::new();
static KILL_BEFORE_DEV_FLAG: AtomicBool = AtomicBool::new(false);
#[cfg(unix)]
@@ -205,21 +205,18 @@ pub fn setup(
let child = SharedChild::spawn(&mut command)
.unwrap_or_else(|_| panic!("failed to run `{before_dev}`"));
let child = Arc::new(child);
let child_ = child.clone();
let child = BEFORE_DEV.get_or_init(move || child);
std::thread::spawn(move || {
let status = child_
let status = child
.wait()
.expect("failed to wait on \"beforeDevCommand\"");
if !(status.success() || KILL_BEFORE_DEV_FLAG.load(Ordering::Relaxed)) {
if !(status.success() || KILL_BEFORE_DEV_FLAG.load(Ordering::SeqCst)) {
log::error!("The \"beforeDevCommand\" terminated with a non-zero status code.");
exit(status.code().unwrap_or(1));
}
});
BEFORE_DEV.set(Mutex::new(child)).unwrap();
let _ = ctrlc::set_handler(move || {
kill_before_dev_process();
exit(130);
@@ -336,11 +333,10 @@ pub fn on_app_exit(code: Option<i32>, reason: ExitReason, exit_on_panic: bool, n
pub fn kill_before_dev_process() {
if let Some(child) = BEFORE_DEV.get() {
let child = child.lock().unwrap();
if KILL_BEFORE_DEV_FLAG.load(Ordering::Relaxed) {
if KILL_BEFORE_DEV_FLAG.load(Ordering::SeqCst) {
return;
}
KILL_BEFORE_DEV_FLAG.store(true, Ordering::Relaxed);
KILL_BEFORE_DEV_FLAG.store(true, Ordering::SeqCst);
#[cfg(windows)]
{
let powershell_path = std::env::var("SYSTEMROOT").map_or_else(

View File

@@ -210,7 +210,7 @@ impl Rust {
if options.no_watch {
let (tx, rx) = sync_channel(1);
self.run_dev(options, run_args, move |status, reason| {
self.run_dev(options, &run_args, move |status, reason| {
on_exit(status, reason);
tx.send(()).unwrap();
})?;
@@ -225,9 +225,11 @@ impl Rust {
&merge_configs,
|rust: &mut Rust, _config| {
let on_exit = on_exit.clone();
rust.run_dev(options.clone(), run_args.clone(), move |status, reason| {
rust
.run_dev(options.clone(), &run_args, move |status, reason| {
on_exit(status, reason)
})
.map(|child| Box::new(child) as Box<dyn DevProcess + Send>)
},
dirs,
)
@@ -361,7 +363,7 @@ fn build_ignore_matcher(dir: &Path) -> IgnoreMatcher {
ignore_builder.add(path);
if let Ok(ignore_file) = std::env::var("TAURI_CLI_WATCHER_IGNORE_FILENAME") {
if let Some(ignore_file) = std::env::var_os("TAURI_CLI_WATCHER_IGNORE_FILENAME") {
ignore_builder.add(dir.join(ignore_file));
}
@@ -393,7 +395,7 @@ fn lookup<F: FnMut(FileType, PathBuf)>(dir: &Path, mut f: F) {
let mut builder = ignore::WalkBuilder::new(dir);
builder.add_custom_ignore_filename(".taurignore");
let _ = builder.add_ignore(default_gitignore);
if let Ok(ignore_file) = std::env::var("TAURI_CLI_WATCHER_IGNORE_FILENAME") {
if let Some(ignore_file) = std::env::var_os("TAURI_CLI_WATCHER_IGNORE_FILENAME") {
builder.add_ignore(ignore_file);
}
builder.require_git(false).ignore(false).max_depth(Some(1));
@@ -490,9 +492,9 @@ impl Rust {
fn run_dev<F: Fn(Option<i32>, ExitReason) + Send + Sync + 'static>(
&mut self,
options: Options,
run_args: Vec<String>,
run_args: &[String],
on_exit: F,
) -> crate::Result<Box<dyn DevProcess + Send>> {
) -> crate::Result<desktop::DevChild> {
desktop::run_dev(
options,
run_args,
@@ -500,7 +502,6 @@ impl Rust {
self.config_features.clone(),
on_exit,
)
.map(|c| Box::new(c) as Box<dyn DevProcess + Send>)
}
fn run_dev_watcher<
@@ -1380,7 +1381,7 @@ fn tauri_config_to_bundle_settings(
if enabled_features.contains(&"tray-icon".into())
|| enabled_features.contains(&"tauri/tray-icon".into())
{
let (tray_kind, path) = std::env::var("TAURI_LINUX_AYATANA_APPINDICATOR")
let (tray_kind, path) = std::env::var_os("TAURI_LINUX_AYATANA_APPINDICATOR")
.map(|ayatana| {
if ayatana == "true" || ayatana == "1" {
(
@@ -1402,7 +1403,7 @@ fn tauri_config_to_bundle_settings(
)
}
})
.unwrap_or_else(|_| pkgconfig_utils::get_appindicator_library_path());
.unwrap_or_else(pkgconfig_utils::get_appindicator_library_path);
match tray_kind {
pkgconfig_utils::TrayKind::Ayatana => {
depends_deb.push("libayatana-appindicator3-1".into());

View File

@@ -29,7 +29,7 @@ pub struct DevChild {
impl DevProcess for DevChild {
fn kill(&self) -> std::io::Result<()> {
self.dev_child.kill()?;
self.manually_killed_app.store(true, Ordering::Relaxed);
self.manually_killed_app.store(true, Ordering::SeqCst);
Ok(())
}
@@ -42,17 +42,17 @@ impl DevProcess for DevChild {
}
fn manually_killed_process(&self) -> bool {
self.manually_killed_app.load(Ordering::Relaxed)
self.manually_killed_app.load(Ordering::SeqCst)
}
}
pub fn run_dev<F: Fn(Option<i32>, ExitReason) + Send + Sync + 'static>(
options: Options,
run_args: Vec<String>,
run_args: &[String],
available_targets: &mut Option<Vec<RustupTarget>>,
config_features: Vec<String>,
on_exit: F,
) -> crate::Result<impl DevProcess> {
) -> crate::Result<DevChild> {
let mut dev_cmd = cargo_command(true, options, available_targets, config_features)?;
let runner = dev_cmd.get_program().to_string_lossy().into_owned();
@@ -137,7 +137,7 @@ pub fn run_dev<F: Fn(Option<i32>, ExitReason) + Send + Sync + 'static>(
status.code(),
if status.code() == Some(101) && is_cargo_compile_error {
ExitReason::CompilationFailed
} else if manually_killed_app_.load(Ordering::Relaxed) {
} else if manually_killed_app_.load(Ordering::SeqCst) {
ExitReason::TriggeredKill
} else {
ExitReason::NormalExit
@@ -163,7 +163,7 @@ pub fn build(
let out_dir = app_settings.out_dir(&options, tauri_dir)?;
let bin_path = app_settings.app_binary_path(&options, tauri_dir)?;
if !std::env::var("STATIC_VCRUNTIME").is_ok_and(|v| v == "false") {
if !std::env::var_os("STATIC_VCRUNTIME").is_some_and(|v| v == "false") {
std::env::set_var("STATIC_VCRUNTIME", "true");
}

View File

@@ -62,7 +62,6 @@ pub fn command(options: Options) -> Result<()> {
)?
};
let (config, metadata) = {
let (config, metadata) = get_config(
&get_app(
MobileTarget::Android,
@@ -74,8 +73,6 @@ pub fn command(options: Options) -> Result<()> {
&[],
&cli_options,
);
(config, metadata)
};
ensure_init(
&tauri_config,

View File

@@ -153,7 +153,6 @@ pub fn run(
.unwrap();
build_options.target = Some(first_target.triple.into());
let (interface, config, metadata) = {
let interface = AppInterface::new(tauri_config, build_options.target.clone(), dirs.tauri)?;
interface.build_options(&mut Vec::new(), &mut build_options.features, true);
@@ -164,8 +163,6 @@ pub fn run(
&build_options.features,
&Default::default(),
);
(interface, config, metadata)
};
let profile = if options.debug {
Profile::Debug

View File

@@ -183,7 +183,6 @@ fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<
.unwrap_or_else(|| Target::all().values().next().unwrap().triple.into());
dev_options.target = Some(target_triple);
let (interface, config, metadata) = {
let interface = AppInterface::new(&tauri_config, dev_options.target.clone(), dirs.tauri)?;
let app = get_app(MobileTarget::Android, &tauri_config, &interface, dirs.tauri);
@@ -193,8 +192,6 @@ fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<
dev_options.features.as_ref(),
&Default::default(),
);
(interface, config, metadata)
};
set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?;

View File

@@ -194,20 +194,17 @@ pub fn run(options: Options, noise_level: NoiseLevel, dirs: &Dirs) -> Result<Bui
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
dirs.tauri,
)?;
let (interface, mut config) = {
let interface = AppInterface::new(&tauri_config, build_options.target.clone(), dirs.tauri)?;
interface.build_options(&mut Vec::new(), &mut build_options.features, true);
let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri);
let (config, _metadata) = get_config(
let (mut config, _) = get_config(
&app,
&tauri_config,
&build_options.features,
&Default::default(),
dirs.tauri,
)?;
(interface, config)
};
set_current_dir(dirs.tauri).context("failed to set current directory")?;

View File

@@ -188,11 +188,10 @@ fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
dirs.tauri,
)?;
let (interface, config) = {
let interface = AppInterface::new(&tauri_config, Some(target_triple), dirs.tauri)?;
let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri);
let (config, _metadata) = get_config(
let (config, _) = get_config(
&app,
&tauri_config,
&dev_options.features,
@@ -200,9 +199,6 @@ fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<
dirs.tauri,
)?;
(interface, config)
};
set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?;
ensure_init(

View File

@@ -95,8 +95,7 @@ pub fn command(options: Options) -> Result<()> {
let macos = macos_from_platform(&options.platform);
let mut tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, &[], dirs.tauri)?;
let cli_options = {
let cli_options = { read_options(&tauri_config) };
let cli_options = read_options(&tauri_config);
if !cli_options.config.is_empty() {
// reload config with merges from the ios dev|build script
reload_tauri_config(
@@ -110,11 +109,6 @@ pub fn command(options: Options) -> Result<()> {
)?
};
cli_options
};
let (config, metadata) = {
let cli_options = read_options(&tauri_config);
let (config, metadata) = get_config(
&get_app(
MobileTarget::Ios,
@@ -127,8 +121,7 @@ pub fn command(options: Options) -> Result<()> {
&cli_options,
dirs.tauri,
)?;
(config, metadata)
};
ensure_init(
&tauri_config,
config.app(),

View File

@@ -67,14 +67,9 @@ impl DevChild {
impl DevProcess for DevChild {
fn kill(&self) -> std::io::Result<()> {
self.manually_killed_process.store(true, Ordering::Relaxed);
match self.child.kill() {
Ok(_) => Ok(()),
Err(e) => {
self.manually_killed_process.store(false, Ordering::Relaxed);
Err(e)
}
}
self.child.kill()?;
self.manually_killed_process.store(true, Ordering::SeqCst);
Ok(())
}
fn try_wait(&self) -> std::io::Result<Option<ExitStatus>> {
@@ -86,7 +81,7 @@ impl DevProcess for DevChild {
}
fn manually_killed_process(&self) -> bool {
self.manually_killed_process.load(Ordering::Relaxed)
self.manually_killed_process.load(Ordering::SeqCst)
}
}