Procházet zdrojové kódy

refactor(cli): move watch and manifest logic to the Rust impl (#4571)

Lucas Fernandes Nogueira před 3 roky
rodič
revize
573b4c0b3c

+ 3 - 6
tooling/cli/src/build.rs

@@ -7,7 +7,6 @@ use crate::{
     app_paths::{app_dir, tauri_dir},
     command_env,
     config::{get as get_config, AppUrl, WindowUrl},
-    manifest::rewrite_manifest,
     updater_signature::sign_file_from_env_variables,
   },
   interface::{AppInterface, AppSettings, Interface},
@@ -55,7 +54,7 @@ pub struct Options {
 }
 
 pub fn command(mut options: Options) -> Result<()> {
-  let merge_config = if let Some(config) = &options.config {
+  options.config = if let Some(config) = &options.config {
     Some(if config.starts_with('{') {
       config.to_string()
     } else {
@@ -68,9 +67,7 @@ pub fn command(mut options: Options) -> Result<()> {
   let tauri_path = tauri_dir();
   set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
 
-  let config = get_config(merge_config.as_deref())?;
-
-  let manifest = rewrite_manifest(config.clone())?;
+  let config = get_config(options.config.as_deref())?;
 
   let config_guard = config.lock().unwrap();
   let config_ = config_guard.as_ref().unwrap();
@@ -210,7 +207,7 @@ pub fn command(mut options: Options) -> Result<()> {
     }
 
     let settings = app_settings
-      .get_bundler_settings(&options.into(), &manifest, config_, out_dir, package_types)
+      .get_bundler_settings(&options.into(), config_, out_dir, package_types)
       .with_context(|| "failed to build bundler settings")?;
 
     // set env vars used by the bundler

+ 8 - 134
tooling/cli/src/dev.rs

@@ -6,33 +6,26 @@ use crate::{
   helpers::{
     app_paths::{app_dir, tauri_dir},
     command_env,
-    config::{get as get_config, reload as reload_config, AppUrl, ConfigHandle, WindowUrl},
-    manifest::{rewrite_manifest, Manifest},
+    config::{get as get_config, AppUrl, WindowUrl},
   },
-  interface::{AppInterface, DevProcess, ExitReason, Interface},
+  interface::{AppInterface, ExitReason, Interface},
   Result,
 };
 use clap::Parser;
 
 use anyhow::Context;
 use log::{error, info, warn};
-use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
 use once_cell::sync::OnceCell;
 use shared_child::SharedChild;
 
 use std::{
   env::set_current_dir,
-  ffi::OsStr,
-  fs::FileType,
   io::Write,
-  path::{Path, PathBuf},
   process::{exit, Command, ExitStatus, Stdio},
   sync::{
     atomic::{AtomicBool, Ordering},
-    mpsc::channel,
     Arc, Mutex,
   },
-  time::Duration,
 };
 
 static BEFORE_DEV: OnceCell<Mutex<Arc<SharedChild>>> = OnceCell::new();
@@ -41,7 +34,7 @@ static KILL_BEFORE_DEV_FLAG: OnceCell<AtomicBool> = OnceCell::new();
 #[cfg(unix)]
 const KILL_CHILDREN_SCRIPT: &[u8] = include_bytes!("../scripts/kill-children.sh");
 
-const TAURI_DEV_WATCHER_GITIGNORE: &[u8] = include_bytes!("../tauri-dev-watcher.gitignore");
+pub const TAURI_DEV_WATCHER_GITIGNORE: &[u8] = include_bytes!("../tauri-dev-watcher.gitignore");
 
 #[derive(Debug, Clone, Parser)]
 #[clap(about = "Tauri dev", trailing_var_arg(true))]
@@ -60,7 +53,7 @@ pub struct Options {
   exit_on_panic: bool,
   /// JSON string or path to JSON file to merge with tauri.conf.json
   #[clap(short, long)]
-  config: Option<String>,
+  pub config: Option<String>,
   /// Run the code in release mode
   #[clap(long = "release")]
   pub release_mode: bool,
@@ -80,7 +73,7 @@ pub fn command(options: Options) -> Result<()> {
 
 fn command_internal(mut options: Options) -> Result<()> {
   let tauri_path = tauri_dir();
-  let merge_config = if let Some(config) = &options.config {
+  options.config = if let Some(config) = &options.config {
     Some(if config.starts_with('{') {
       config.to_string()
     } else {
@@ -92,7 +85,7 @@ fn command_internal(mut options: Options) -> Result<()> {
 
   set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
 
-  let config = get_config(merge_config.as_deref())?;
+  let config = get_config(options.config.as_deref())?;
 
   if let Some(before_dev) = &config
     .lock()
@@ -167,19 +160,6 @@ fn command_internal(mut options: Options) -> Result<()> {
       .clone();
   }
 
-  let manifest = {
-    let (tx, rx) = channel();
-    let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
-    watcher.watch(tauri_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
-    let manifest = rewrite_manifest(config.clone())?;
-    loop {
-      if let Ok(DebouncedEvent::NoticeWrite(_)) = rx.recv() {
-        break;
-      }
-    }
-    manifest
-  };
-
   let mut cargo_features = config
     .lock()
     .unwrap()
@@ -255,29 +235,9 @@ fn command_internal(mut options: Options) -> Result<()> {
   let mut interface = AppInterface::new(config.lock().unwrap().as_ref().unwrap())?;
 
   let exit_on_panic = options.exit_on_panic;
-  let process = interface.dev(options.clone().into(), &manifest, move |status, reason| {
+  interface.dev(options.into(), move |status, reason| {
     on_dev_exit(status, reason, exit_on_panic)
-  })?;
-  let shared_process = Arc::new(Mutex::new(process));
-
-  if let Err(e) = watch(
-    interface,
-    shared_process.clone(),
-    tauri_path,
-    merge_config,
-    config,
-    options,
-    manifest,
-  ) {
-    shared_process
-      .lock()
-      .unwrap()
-      .kill()
-      .with_context(|| "failed to kill app process")?;
-    Err(e)
-  } else {
-    Ok(())
-  }
+  })
 }
 
 fn on_dev_exit(status: ExitStatus, reason: ExitReason, exit_on_panic: bool) {
@@ -309,92 +269,6 @@ fn check_for_updates() -> Result<()> {
   Ok(())
 }
 
-fn lookup<F: FnMut(FileType, PathBuf)>(dir: &Path, mut f: F) {
-  let mut default_gitignore = std::env::temp_dir();
-  default_gitignore.push(".tauri-dev");
-  let _ = std::fs::create_dir_all(&default_gitignore);
-  default_gitignore.push(".gitignore");
-  if !default_gitignore.exists() {
-    if let Ok(mut file) = std::fs::File::create(default_gitignore.clone()) {
-      let _ = file.write_all(TAURI_DEV_WATCHER_GITIGNORE);
-    }
-  }
-
-  let mut builder = ignore::WalkBuilder::new(dir);
-  let _ = builder.add_ignore(default_gitignore);
-  if let Ok(ignore_file) = std::env::var("TAURI_DEV_WATCHER_IGNORE_FILE") {
-    builder.add_ignore(ignore_file);
-  }
-  builder.require_git(false).ignore(false).max_depth(Some(1));
-
-  for entry in builder.build().flatten() {
-    f(entry.file_type().unwrap(), dir.join(entry.path()));
-  }
-}
-
-#[allow(clippy::too_many_arguments)]
-fn watch<P: DevProcess, I: Interface<Dev = P>>(
-  mut interface: I,
-  process: Arc<Mutex<P>>,
-  tauri_path: PathBuf,
-  merge_config: Option<String>,
-  config: ConfigHandle,
-  options: Options,
-  mut manifest: Manifest,
-) -> Result<()> {
-  let (tx, rx) = channel();
-
-  let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
-  lookup(&tauri_path, |file_type, path| {
-    if path != tauri_path {
-      let _ = watcher.watch(
-        path,
-        if file_type.is_dir() {
-          RecursiveMode::Recursive
-        } else {
-          RecursiveMode::NonRecursive
-        },
-      );
-    }
-  });
-
-  let exit_on_panic = options.exit_on_panic;
-
-  loop {
-    if let Ok(event) = rx.recv() {
-      let event_path = match event {
-        DebouncedEvent::Create(path) => Some(path),
-        DebouncedEvent::Remove(path) => Some(path),
-        DebouncedEvent::Rename(_, dest) => Some(dest),
-        DebouncedEvent::Write(path) => Some(path),
-        _ => None,
-      };
-
-      if let Some(event_path) = event_path {
-        if event_path.file_name() == Some(OsStr::new("tauri.conf.json")) {
-          reload_config(merge_config.as_deref())?;
-          manifest = rewrite_manifest(config.clone())?;
-        } else {
-          // When tauri.conf.json is changed, rewrite_manifest will be called
-          // which will trigger the watcher again
-          // So the app should only be started when a file other than tauri.conf.json is changed
-          let mut p = process.lock().unwrap();
-          p.kill().with_context(|| "failed to kill app process")?;
-          // wait for the process to exit
-          loop {
-            if let Ok(Some(_)) = p.try_wait() {
-              break;
-            }
-          }
-          *p = interface.dev(options.clone().into(), &manifest, move |status, reason| {
-            on_dev_exit(status, reason, exit_on_panic)
-          })?;
-        }
-      }
-    }
-  }
-}
-
 fn kill_before_dev_process() {
   if let Some(child) = BEFORE_DEV.get() {
     let child = child.lock().unwrap();

+ 2 - 3
tooling/cli/src/helpers/config.rs

@@ -102,7 +102,6 @@ pub fn get(merge_config: Option<&str>) -> crate::Result<ConfigHandle> {
   get_internal(merge_config, false)
 }
 
-pub fn reload(merge_config: Option<&str>) -> crate::Result<()> {
-  get_internal(merge_config, true)?;
-  Ok(())
+pub fn reload(merge_config: Option<&str>) -> crate::Result<ConfigHandle> {
+  get_internal(merge_config, true)
 }

+ 0 - 1
tooling/cli/src/helpers/mod.rs

@@ -5,7 +5,6 @@
 pub mod app_paths;
 pub mod config;
 pub mod framework;
-pub mod manifest;
 pub mod template;
 pub mod updater_signature;
 

+ 4 - 13
tooling/cli/src/interface/mod.rs

@@ -9,7 +9,7 @@ use std::{
   process::ExitStatus,
 };
 
-use crate::helpers::{config::Config, manifest::Manifest};
+use crate::helpers::config::Config;
 use tauri_bundler::bundle::{PackageType, Settings, SettingsBuilder};
 
 pub use rust::{Options, Rust as AppInterface};
@@ -19,7 +19,6 @@ pub trait AppSettings {
   fn get_bundle_settings(
     &self,
     config: &Config,
-    manifest: &Manifest,
     features: &[String],
   ) -> crate::Result<tauri_bundler::BundleSettings>;
   fn app_binary_path(&self, options: &Options) -> crate::Result<PathBuf>;
@@ -32,7 +31,6 @@ pub trait AppSettings {
   fn get_bundler_settings(
     &self,
     options: &Options,
-    manifest: &Manifest,
     config: &Config,
     out_dir: &Path,
     package_types: Option<Vec<PackageType>>,
@@ -51,7 +49,7 @@ pub trait AppSettings {
 
     let mut settings_builder = SettingsBuilder::new()
       .package_settings(self.get_package_settings())
-      .bundle_settings(self.get_bundle_settings(config, manifest, &enabled_features)?)
+      .bundle_settings(self.get_bundle_settings(config, &enabled_features)?)
       .binaries(self.get_binaries(config, &target)?)
       .project_out_directory(out_dir)
       .target(target);
@@ -64,11 +62,6 @@ pub trait AppSettings {
   }
 }
 
-pub trait DevProcess {
-  fn kill(&self) -> std::io::Result<()>;
-  fn try_wait(&self) -> std::io::Result<Option<ExitStatus>>;
-}
-
 #[derive(Debug)]
 pub enum ExitReason {
   /// Killed manually.
@@ -81,15 +74,13 @@ pub enum ExitReason {
 
 pub trait Interface: Sized {
   type AppSettings: AppSettings;
-  type Dev: DevProcess;
 
   fn new(config: &Config) -> crate::Result<Self>;
   fn app_settings(&self) -> &Self::AppSettings;
   fn build(&mut self, options: Options) -> crate::Result<()>;
-  fn dev<F: FnOnce(ExitStatus, ExitReason) + Send + 'static>(
+  fn dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
     &mut self,
     options: Options,
-    manifest: &Manifest,
     on_exit: F,
-  ) -> crate::Result<Self::Dev>;
+  ) -> crate::Result<()>;
 }

+ 165 - 46
tooling/cli/src/interface/rust.rs

@@ -3,21 +3,25 @@
 // SPDX-License-Identifier: MIT
 
 use std::{
-  fs::{rename, File},
+  ffi::OsStr,
+  fs::{rename, File, FileType},
   io::{BufReader, ErrorKind, Read, Write},
   path::{Path, PathBuf},
   process::{Command, ExitStatus, Stdio},
   str::FromStr,
   sync::{
     atomic::{AtomicBool, Ordering},
+    mpsc::channel,
     Arc, Mutex,
   },
+  time::Duration,
 };
 
 use anyhow::Context;
 #[cfg(target_os = "linux")]
 use heck::ToKebabCase;
 use log::warn;
+use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
 use serde::Deserialize;
 use shared_child::SharedChild;
 use tauri_bundler::{
@@ -25,16 +29,18 @@ use tauri_bundler::{
   UpdaterSettings, WindowsSettings,
 };
 
-use super::{AppSettings, DevProcess, ExitReason, Interface};
+use super::{AppSettings, ExitReason, Interface};
 use crate::{
   helpers::{
     app_paths::tauri_dir,
-    config::{wix_settings, Config},
-    manifest::Manifest,
+    config::{reload as reload_config, wix_settings, Config},
   },
   CommandExt,
 };
 
+mod manifest;
+use manifest::{rewrite_manifest, Manifest};
+
 #[derive(Debug, Clone)]
 pub struct Options {
   pub runner: Option<String>,
@@ -42,6 +48,7 @@ pub struct Options {
   pub target: Option<String>,
   pub features: Option<Vec<String>>,
   pub args: Vec<String>,
+  pub config: Option<String>,
 }
 
 impl From<crate::build::Options> for Options {
@@ -52,6 +59,7 @@ impl From<crate::build::Options> for Options {
       target: options.target,
       features: options.features,
       args: options.args,
+      config: options.config,
     }
   }
 }
@@ -64,6 +72,7 @@ impl From<crate::dev::Options> for Options {
       target: options.target,
       features: options.features,
       args: options.args,
+      config: options.config,
     }
   }
 }
@@ -74,7 +83,7 @@ pub struct DevChild {
   app_child: Arc<Mutex<Option<Arc<SharedChild>>>>,
 }
 
-impl DevProcess for DevChild {
+impl DevChild {
   fn kill(&self) -> std::io::Result<()> {
     if let Some(child) = &*self.app_child.lock().unwrap() {
       child.kill()?;
@@ -109,11 +118,22 @@ pub struct Rust {
 
 impl Interface for Rust {
   type AppSettings = RustAppSettings;
-  type Dev = DevChild;
 
   fn new(config: &Config) -> crate::Result<Self> {
+    let manifest = {
+      let (tx, rx) = channel();
+      let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
+      watcher.watch(tauri_dir().join("Cargo.toml"), RecursiveMode::Recursive)?;
+      let manifest = rewrite_manifest(config)?;
+      loop {
+        if let Ok(DebouncedEvent::NoticeWrite(_)) = rx.recv() {
+          break;
+        }
+      }
+      manifest
+    };
     Ok(Self {
-      app_settings: RustAppSettings::new(config)?,
+      app_settings: RustAppSettings::new(config, manifest)?,
       config_features: config.build.features.clone().unwrap_or_default(),
       product_name: config.package.product_name.clone(),
       available_targets: None,
@@ -172,12 +192,87 @@ impl Interface for Rust {
     Ok(())
   }
 
-  fn dev<F: FnOnce(ExitStatus, ExitReason) + Send + 'static>(
+  fn dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
+    &mut self,
+    options: Options,
+    on_exit: F,
+  ) -> crate::Result<()> {
+    let on_exit = Arc::new(on_exit);
+
+    let on_exit_ = on_exit.clone();
+    let child = self.run_dev(options.clone(), move |status, reason| {
+      on_exit_(status, reason)
+    })?;
+
+    self.run_dev_watcher(child, options, on_exit)
+  }
+}
+
+fn lookup<F: FnMut(FileType, PathBuf)>(dir: &Path, mut f: F) {
+  let mut default_gitignore = std::env::temp_dir();
+  default_gitignore.push(".tauri-dev");
+  let _ = std::fs::create_dir_all(&default_gitignore);
+  default_gitignore.push(".gitignore");
+  if !default_gitignore.exists() {
+    if let Ok(mut file) = std::fs::File::create(default_gitignore.clone()) {
+      let _ = file.write_all(crate::dev::TAURI_DEV_WATCHER_GITIGNORE);
+    }
+  }
+
+  let mut builder = ignore::WalkBuilder::new(dir);
+  let _ = builder.add_ignore(default_gitignore);
+  if let Ok(ignore_file) = std::env::var("TAURI_DEV_WATCHER_IGNORE_FILE") {
+    builder.add_ignore(ignore_file);
+  }
+  builder.require_git(false).ignore(false).max_depth(Some(1));
+
+  for entry in builder.build().flatten() {
+    f(entry.file_type().unwrap(), dir.join(entry.path()));
+  }
+}
+
+impl Rust {
+  fn fetch_available_targets(&mut self) {
+    if let Ok(output) = Command::new("rustup").args(["target", "list"]).output() {
+      let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
+      self.available_targets.replace(
+        stdout
+          .split('\n')
+          .map(|t| {
+            let mut s = t.split(' ');
+            let name = s.next().unwrap().to_string();
+            let installed = s.next().map(|v| v == "(installed)").unwrap_or_default();
+            Target { name, installed }
+          })
+          .filter(|t| !t.name.is_empty())
+          .collect(),
+      );
+    }
+  }
+
+  fn validate_target(&self, target: &str) -> crate::Result<()> {
+    if let Some(available_targets) = &self.available_targets {
+      if let Some(target) = available_targets.iter().find(|t| t.name == target) {
+        if !target.installed {
+          anyhow::bail!(
+            "Target {target} is not installed (installed targets: {installed}). Please run `rustup target add {target}`.",
+            target = target.name,
+            installed = available_targets.iter().filter(|t| t.installed).map(|t| t.name.as_str()).collect::<Vec<&str>>().join(", ")
+          );
+        }
+      }
+      if !available_targets.iter().any(|t| t.name == target) {
+        anyhow::bail!("Target {target} does not exist. Please run `rustup target list` to see the available targets.", target = target);
+      }
+    }
+    Ok(())
+  }
+
+  fn run_dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
     &mut self,
     options: Options,
-    manifest: &Manifest,
     on_exit: F,
-  ) -> crate::Result<Self::Dev> {
+  ) -> crate::Result<DevChild> {
     let bin_path = self.app_settings.app_binary_path(&options)?;
     let product_name = self.product_name.clone();
 
@@ -207,7 +302,7 @@ impl Interface for Rust {
     build_cmd.arg("build").arg("--color").arg("always");
 
     if !options.args.contains(&"--no-default-features".into()) {
-      let manifest_features = manifest.features();
+      let manifest_features = self.app_settings.manifest.features();
       let enable_features: Vec<String> = manifest_features
         .get("default")
         .cloned()
@@ -356,43 +451,66 @@ impl Interface for Rust {
       app_child,
     })
   }
-}
 
-impl Rust {
-  fn fetch_available_targets(&mut self) {
-    if let Ok(output) = Command::new("rustup").args(["target", "list"]).output() {
-      let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
-      self.available_targets.replace(
-        stdout
-          .split('\n')
-          .map(|t| {
-            let mut s = t.split(' ');
-            let name = s.next().unwrap().to_string();
-            let installed = s.next().map(|v| v == "(installed)").unwrap_or_default();
-            Target { name, installed }
-          })
-          .filter(|t| !t.name.is_empty())
-          .collect(),
-      );
-    }
-  }
+  fn run_dev_watcher<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
+    &mut self,
+    child: DevChild,
+    options: Options,
+    on_exit: Arc<F>,
+  ) -> crate::Result<()> {
+    let process = Arc::new(Mutex::new(child));
+    let (tx, rx) = channel();
+    let tauri_path = tauri_dir();
+
+    let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
+    lookup(&tauri_path, |file_type, path| {
+      if path != tauri_path {
+        let _ = watcher.watch(
+          path,
+          if file_type.is_dir() {
+            RecursiveMode::Recursive
+          } else {
+            RecursiveMode::NonRecursive
+          },
+        );
+      }
+    });
 
-  fn validate_target(&self, target: &str) -> crate::Result<()> {
-    if let Some(available_targets) = &self.available_targets {
-      if let Some(target) = available_targets.iter().find(|t| t.name == target) {
-        if !target.installed {
-          anyhow::bail!(
-            "Target {target} is not installed (installed targets: {installed}). Please run `rustup target add {target}`.",
-            target = target.name,
-            installed = available_targets.iter().filter(|t| t.installed).map(|t| t.name.as_str()).collect::<Vec<&str>>().join(", ")
-          );
+    loop {
+      let on_exit = on_exit.clone();
+      if let Ok(event) = rx.recv() {
+        let event_path = match event {
+          DebouncedEvent::Create(path) => Some(path),
+          DebouncedEvent::Remove(path) => Some(path),
+          DebouncedEvent::Rename(_, dest) => Some(dest),
+          DebouncedEvent::Write(path) => Some(path),
+          _ => None,
+        };
+
+        if let Some(event_path) = event_path {
+          if event_path.file_name() == Some(OsStr::new("tauri.conf.json")) {
+            let config = reload_config(options.config.as_deref())?;
+            self.app_settings.manifest =
+              rewrite_manifest(config.lock().unwrap().as_ref().unwrap())?;
+          } else {
+            // When tauri.conf.json is changed, rewrite_manifest will be called
+            // which will trigger the watcher again
+            // So the app should only be started when a file other than tauri.conf.json is changed
+            let mut p = process.lock().unwrap();
+            p.kill().with_context(|| "failed to kill app process")?;
+            // wait for the process to exit
+            loop {
+              if let Ok(Some(_)) = p.try_wait() {
+                break;
+              }
+            }
+            *p = self.run_dev(options.clone(), move |status, reason| {
+              on_exit(status, reason)
+            })?;
+          }
         }
       }
-      if !available_targets.iter().any(|t| t.name == target) {
-        anyhow::bail!("Target {target} does not exist. Please run `rustup target list` to see the available targets.", target = target);
-      }
     }
-    Ok(())
   }
 
   fn build_app(&mut self, options: Options) -> crate::Result<()> {
@@ -533,6 +651,7 @@ struct CargoConfig {
 }
 
 pub struct RustAppSettings {
+  manifest: Manifest,
   cargo_settings: CargoSettings,
   cargo_package_settings: CargoPackageSettings,
   package_settings: PackageSettings,
@@ -546,11 +665,10 @@ impl AppSettings for RustAppSettings {
   fn get_bundle_settings(
     &self,
     config: &Config,
-    manifest: &Manifest,
     features: &[String],
   ) -> crate::Result<BundleSettings> {
     tauri_config_to_bundle_settings(
-      manifest,
+      &self.manifest,
       features,
       config.tauri.bundle.clone(),
       config.tauri.system_tray.clone(),
@@ -690,7 +808,7 @@ impl AppSettings for RustAppSettings {
 }
 
 impl RustAppSettings {
-  pub fn new(config: &Config) -> crate::Result<Self> {
+  pub fn new(config: &Config, manifest: Manifest) -> crate::Result<Self> {
     let cargo_settings =
       CargoSettings::load(&tauri_dir()).with_context(|| "failed to load cargo settings")?;
     let cargo_package_settings = match &cargo_settings.package {
@@ -725,6 +843,7 @@ impl RustAppSettings {
     };
 
     Ok(Self {
+      manifest,
       cargo_settings,
       cargo_package_settings,
       package_settings,

+ 4 - 7
tooling/cli/src/helpers/manifest.rs → tooling/cli/src/interface/rust/manifest.rs

@@ -2,9 +2,9 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-use super::{
+use crate::helpers::{
   app_paths::tauri_dir,
-  config::{ConfigHandle, PatternKind},
+  config::{Config, PatternKind},
 };
 
 use anyhow::Context;
@@ -184,13 +184,10 @@ fn write_features(
   }
 }
 
-pub fn rewrite_manifest(config: ConfigHandle) -> crate::Result<Manifest> {
+pub fn rewrite_manifest(config: &Config) -> crate::Result<Manifest> {
   let manifest_path = tauri_dir().join("Cargo.toml");
   let mut manifest = read_manifest(&manifest_path)?;
 
-  let config_guard = config.lock().unwrap();
-  let config = config_guard.as_ref().unwrap();
-
   let mut tauri_build_features = HashSet::new();
   if let PatternKind::Isolation { .. } = config.tauri.pattern {
     tauri_build_features.insert("isolation".to_string());
@@ -209,7 +206,7 @@ pub fn rewrite_manifest(config: ConfigHandle) -> crate::Result<Manifest> {
 
   let mut tauri_features =
     HashSet::from_iter(config.tauri.features().into_iter().map(|f| f.to_string()));
-  let cli_managed_tauri_features = super::config::TauriConfig::all_features();
+  let cli_managed_tauri_features = crate::helpers::config::TauriConfig::all_features();
   let res = match write_features(
     manifest
       .as_table_mut()