From 28fb036ce476c6f22815c35385f923135212c6f3 Mon Sep 17 00:00:00 2001 From: Sam Willis Date: Sun, 18 Feb 2024 18:10:21 +0000 Subject: [PATCH] fix(core): Incorrect resource_dir when app run from new style target/PLATFORM+ARCH/(debug|release) dir (#8852) * Fix resource_dir when app run from new target/someting/(debug|release) dir * Update core/tauri-utils/src/platform.rs Co-authored-by: Amr Bashir * change file, update logic, add tests * lint * fix tests --------- Co-authored-by: Amr Bashir Co-authored-by: Lucas Nogueira --- .changes/enhance-resource-dir-resolution.md | 5 ++ core/tauri-config-schema/schema.json | 9 +- core/tauri-utils/src/platform.rs | 91 +++++++++++++++++++-- tooling/cli/schema.json | 9 +- 4 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 .changes/enhance-resource-dir-resolution.md diff --git a/.changes/enhance-resource-dir-resolution.md b/.changes/enhance-resource-dir-resolution.md new file mode 100644 index 000000000..2d0edc5e3 --- /dev/null +++ b/.changes/enhance-resource-dir-resolution.md @@ -0,0 +1,5 @@ +--- +"tauri-utils": patch:enhance +--- + +Enhance resource directory resolution on development. diff --git a/core/tauri-config-schema/schema.json b/core/tauri-config-schema/schema.json index 0a9c13589..d7534cfbc 100644 --- a/core/tauri-config-schema/schema.json +++ b/core/tauri-config-schema/schema.json @@ -1095,7 +1095,14 @@ ] }, "windows": { - "description": "List of windows that uses this capability. Can be a glob pattern.", + "description": "List of windows that uses this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that uses this capability. Can be a glob pattern.\n\nThis is only required when using on multiwebview contexts, by default all child webviews of a window that matches [`Self::windows`] are linked.", "type": "array", "items": { "type": "string" diff --git a/core/tauri-utils/src/platform.rs b/core/tauri-utils/src/platform.rs index c54f71d35..9600310af 100644 --- a/core/tauri-utils/src/platform.rs +++ b/core/tauri-utils/src/platform.rs @@ -6,7 +6,7 @@ use std::{ fmt::Display, - path::{PathBuf, MAIN_SEPARATOR}, + path::{Path, PathBuf, MAIN_SEPARATOR}, }; use serde::{Deserialize, Serialize}; @@ -221,6 +221,28 @@ pub fn target_triple() -> crate::Result { Ok(format!("{arch}-{os}")) } +#[cfg(not(test))] +fn is_cargo_output_directory(path: &Path) -> bool { + path.join(".cargo-lock").exists() +} + +#[cfg(test)] +const CARGO_OUTPUT_DIRECTORIES: &[&str] = &["debug", "release", "custom-profile"]; + +#[cfg(test)] +fn is_cargo_output_directory(path: &Path) -> bool { + let last_component = path + .components() + .last() + .unwrap() + .as_os_str() + .to_str() + .unwrap(); + CARGO_OUTPUT_DIRECTORIES + .iter() + .any(|dirname| &last_component == dirname) +} + /// Computes the resource directory of the current environment. /// /// On Windows, it's the path to the executable. @@ -233,17 +255,32 @@ pub fn target_triple() -> crate::Result { /// `${exe_dir}/../lib/${exe_name}`. /// /// On MacOS, it's `${exe_dir}../Resources` (inside .app). -#[allow(unused_variables)] pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> crate::Result { let exe = current_exe()?; - let exe_dir = exe.parent().expect("failed to get exe directory"); + resource_dir_from(exe, package_info, env) +} + +#[allow(unused_variables)] +fn resource_dir_from>( + exe: P, + package_info: &PackageInfo, + env: &Env, +) -> crate::Result { + let exe_dir = exe.as_ref().parent().expect("failed to get exe directory"); let curr_dir = exe_dir.display().to_string(); - if curr_dir.ends_with(format!("{MAIN_SEPARATOR}target{MAIN_SEPARATOR}debug").as_str()) - || curr_dir.ends_with(format!("{MAIN_SEPARATOR}target{MAIN_SEPARATOR}release").as_str()) - || cfg!(target_os = "windows") + let parts: Vec<&str> = curr_dir.split(MAIN_SEPARATOR).collect(); + let len = parts.len(); + + // Check if running from the Cargo output directory, which means it's an executable in a development machine + // We check if the binary is inside a `target` folder which can be either `target/$profile` or `target/$triple/$profile` + // and see if there's a .cargo-lock file along the executable + // This ensures the check is safer so it doesn't affect apps in production + // Windows also includes the resources in the executable folder so we check that too + if cfg!(target_os = "windows") + || ((len >= 2 && parts[len - 2] == "target") || (len >= 3 && parts[len - 3] == "target")) + && is_cargo_output_directory(exe_dir) { - // running from the out dir or windows return Ok(exe_dir.to_path_buf()); } @@ -306,3 +343,43 @@ mod build { } } } + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use crate::{Env, PackageInfo}; + + #[test] + fn resolve_resource_dir() { + let package_info = PackageInfo { + name: "MyApp".into(), + version: "1.0.0".parse().unwrap(), + authors: "", + description: "", + crate_name: "", + }; + let env = Env::default(); + + let path = PathBuf::from("/path/to/target/aarch64-apple-darwin/debug/app"); + let resource_dir = super::resource_dir_from(&path, &package_info, &env).unwrap(); + assert_eq!(resource_dir, path.parent().unwrap()); + + let path = PathBuf::from("/path/to/target/custom-profile/app"); + let resource_dir = super::resource_dir_from(&path, &package_info, &env).unwrap(); + assert_eq!(resource_dir, path.parent().unwrap()); + + let path = PathBuf::from("/path/to/target/release/app"); + let resource_dir = super::resource_dir_from(&path, &package_info, &env).unwrap(); + assert_eq!(resource_dir, path.parent().unwrap()); + + let path = PathBuf::from("/path/to/target/unknown-profile/app"); + let resource_dir = super::resource_dir_from(&path, &package_info, &env); + #[cfg(target_os = "macos")] + assert!(resource_dir.is_err()); + #[cfg(target_os = "linux")] + assert_eq!(resource_dir.unwrap(), PathBuf::from("/usr/lib/my-app")); + #[cfg(windows)] + assert_eq!(resource_dir.unwrap(), path.parent().unwrap()); + } +} diff --git a/tooling/cli/schema.json b/tooling/cli/schema.json index 0a9c13589..d7534cfbc 100644 --- a/tooling/cli/schema.json +++ b/tooling/cli/schema.json @@ -1095,7 +1095,14 @@ ] }, "windows": { - "description": "List of windows that uses this capability. Can be a glob pattern.", + "description": "List of windows that uses this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that uses this capability. Can be a glob pattern.\n\nThis is only required when using on multiwebview contexts, by default all child webviews of a window that matches [`Self::windows`] are linked.", "type": "array", "items": { "type": "string"