diff --git a/core/tauri-build/src/lib.rs b/core/tauri-build/src/lib.rs index 3663d5366..e49067aed 100644 --- a/core/tauri-build/src/lib.rs +++ b/core/tauri-build/src/lib.rs @@ -109,7 +109,7 @@ pub fn build() { pub fn try_build(attributes: Attributes) -> Result<()> { use anyhow::anyhow; use cargo_toml::{Dependency, Manifest}; - use tauri_utils::config::Config; + use tauri_utils::config::{Config, TauriConfig}; println!("cargo:rerun-if-changed=src/Cargo.toml"); println!("cargo:rerun-if-changed=tauri.conf.json"); @@ -126,18 +126,53 @@ pub fn try_build(attributes: Attributes) -> Result<()> { let mut manifest = Manifest::from_path("Cargo.toml")?; if let Some(tauri) = manifest.dependencies.remove("tauri") { - let mut features = match tauri { + let features = match tauri { Dependency::Simple(_) => Vec::new(), Dependency::Detailed(dep) => dep.features, }; - features.sort(); - let expected_features = config.tauri.features(); - if features != expected_features { + let all_cli_managed_features = TauriConfig::all_features(); + let diff = features_diff( + &features + .into_iter() + .filter(|f| all_cli_managed_features.contains(&f.as_str())) + .collect::>(), + &config + .tauri + .features() + .into_iter() + .map(|f| f.to_string()) + .collect::>(), + ); + + let mut error_message = String::new(); + if !diff.remove.is_empty() { + error_message.push_str("remove the `"); + error_message.push_str(&diff.remove.join(", ").to_string()); + error_message.push_str(if diff.remove.len() == 1 { + "` feature" + } else { + "` features" + }); + if !diff.add.is_empty() { + error_message.push_str(" and "); + } + } + if !diff.add.is_empty() { + error_message.push_str("add the `"); + error_message.push_str(&diff.add.join(", ").to_string()); + error_message.push_str(if diff.add.len() == 1 { + "` feature" + } else { + "` features" + }); + } + + if !error_message.is_empty() { return Err(anyhow!(" The `tauri` dependency features on the `Cargo.toml` file does not match the allowlist defined under `tauri.conf.json`. - Please run `tauri dev` or `tauri build` or set it to {:?}. - ", expected_features)); + Please run `tauri dev` or `tauri build` or {}. + ", error_message)); } } @@ -188,3 +223,66 @@ pub fn try_build(attributes: Attributes) -> Result<()> { Ok(()) } + +#[derive(Debug, Default, PartialEq, Eq)] +struct Diff { + remove: Vec, + add: Vec, +} + +fn features_diff(current: &[String], expected: &[String]) -> Diff { + let mut remove = Vec::new(); + let mut add = Vec::new(); + for feature in current { + if !expected.contains(&feature) { + remove.push(feature.clone()); + } + } + + for feature in expected { + if !current.contains(feature) { + add.push(feature.clone()); + } + } + + Diff { remove, add } +} + +#[cfg(test)] +mod tests { + use super::Diff; + + #[test] + fn array_diff() { + for (current, expected, result) in [ + (vec![], vec![], Default::default()), + ( + vec!["a".into()], + vec![], + Diff { + remove: vec!["a".into()], + add: vec![], + }, + ), + (vec!["a".into()], vec!["a".into()], Default::default()), + ( + vec!["a".into(), "b".into()], + vec!["a".into()], + Diff { + remove: vec!["b".into()], + add: vec![], + }, + ), + ( + vec!["a".into(), "b".into()], + vec!["a".into(), "c".into()], + Diff { + remove: vec!["b".into()], + add: vec!["c".into()], + }, + ), + ] { + assert_eq!(super::features_diff(¤t, &expected), result); + } + } +} diff --git a/core/tauri-utils/src/config.rs b/core/tauri-utils/src/config.rs index 88ed40c55..43df7dc60 100644 --- a/core/tauri-utils/src/config.rs +++ b/core/tauri-utils/src/config.rs @@ -1398,6 +1398,7 @@ pub struct AllowlistConfig { impl Allowlist for AllowlistConfig { fn all_features() -> Vec<&'static str> { let mut features = Vec::new(); + features.push("api-all"); features.extend(FsAllowlistConfig::all_features()); features.extend(WindowAllowlistConfig::all_features()); features.extend(ShellAllowlistConfig::all_features()); @@ -1428,6 +1429,8 @@ impl Allowlist for AllowlistConfig { features.extend(self.os.to_features()); features.extend(self.path.to_features()); features.extend(self.protocol.to_features()); + features.extend(self.process.to_features()); + features.extend(self.clipboard.to_features()); features } }