Skip to content

Commit d340b8c

Browse files
authored
fix(macos): check if path is file or dir or neither (#13793)
1 parent 830146d commit d340b8c

File tree

1 file changed

+165
-6
lines changed
  • crates/tauri-bundler/src/bundle/macos

1 file changed

+165
-6
lines changed

crates/tauri-bundler/src/bundle/macos/app.rs

Lines changed: 165 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use super::{
2828
};
2929
use crate::{
3030
utils::{fs_utils, CommandExt},
31+
Error::GenericError,
3132
Settings,
3233
};
3334

@@ -173,6 +174,12 @@ fn copy_binaries_to_bundle(
173174
/// Copies user-defined files to the app under Contents.
174175
fn copy_custom_files_to_bundle(bundle_directory: &Path, settings: &Settings) -> crate::Result<()> {
175176
for (contents_path, path) in settings.macos().files.iter() {
177+
if !path.try_exists()? {
178+
return Err(GenericError(format!(
179+
"Failed to copy {path:?} to {contents_path:?}. {path:?} does not exist."
180+
)));
181+
}
182+
176183
let contents_path = if contents_path.is_absolute() {
177184
contents_path.strip_prefix("/").unwrap()
178185
} else {
@@ -181,9 +188,13 @@ fn copy_custom_files_to_bundle(bundle_directory: &Path, settings: &Settings) ->
181188
if path.is_file() {
182189
fs_utils::copy_file(path, &bundle_directory.join(contents_path))
183190
.with_context(|| format!("Failed to copy file {path:?} to {contents_path:?}"))?;
184-
} else {
191+
} else if path.is_dir() {
185192
fs_utils::copy_dir(path, &bundle_directory.join(contents_path))
186193
.with_context(|| format!("Failed to copy directory {path:?} to {contents_path:?}"))?;
194+
} else {
195+
return Err(GenericError(format!(
196+
"{path:?} is not a file or directory."
197+
)));
187198
}
188199
}
189200
Ok(())
@@ -405,9 +416,7 @@ fn copy_frameworks_to_bundle(
405416
} else if framework.ends_with(".dylib") {
406417
let src_path = PathBuf::from(framework);
407418
if !src_path.exists() {
408-
return Err(crate::Error::GenericError(format!(
409-
"Library not found: {framework}"
410-
)));
419+
return Err(GenericError(format!("Library not found: {framework}")));
411420
}
412421
let src_name = src_path.file_name().expect("Couldn't get library filename");
413422
let dest_path = dest_dir.join(src_name);
@@ -418,7 +427,7 @@ fn copy_frameworks_to_bundle(
418427
});
419428
continue;
420429
} else if framework.contains('/') {
421-
return Err(crate::Error::GenericError(format!(
430+
return Err(GenericError(format!(
422431
"Framework path should have .framework extension: {framework}"
423432
)));
424433
}
@@ -436,7 +445,7 @@ fn copy_frameworks_to_bundle(
436445
{
437446
continue;
438447
}
439-
return Err(crate::Error::GenericError(format!(
448+
return Err(GenericError(format!(
440449
"Could not locate framework: {framework}"
441450
)));
442451
}
@@ -529,3 +538,153 @@ fn add_nested_code_sign_path(src_path: &Path, dest_path: &Path, sign_paths: &mut
529538
}
530539
}
531540
}
541+
542+
#[cfg(test)]
543+
mod tests {
544+
use super::*;
545+
use crate::bundle::{BundleSettings, MacOsSettings, PackageSettings, SettingsBuilder};
546+
use std::{
547+
collections::HashMap,
548+
fs,
549+
path::{Path, PathBuf},
550+
};
551+
552+
/// Helper that builds a `Settings` instance and bundle directory for tests.
553+
/// It receives a mapping of bundle-relative paths to source paths and
554+
/// returns the generated bundle directory and settings.
555+
fn create_test_bundle(
556+
project_dir: &Path,
557+
files: HashMap<PathBuf, PathBuf>,
558+
) -> (PathBuf, crate::bundle::Settings) {
559+
let macos_settings = MacOsSettings {
560+
files,
561+
..Default::default()
562+
};
563+
564+
let settings = SettingsBuilder::new()
565+
.project_out_directory(project_dir)
566+
.package_settings(PackageSettings {
567+
product_name: "TestApp".into(),
568+
version: "0.1.0".into(),
569+
description: "test".into(),
570+
homepage: None,
571+
authors: None,
572+
default_run: None,
573+
})
574+
.bundle_settings(BundleSettings {
575+
macos: macos_settings,
576+
..Default::default()
577+
})
578+
.target("x86_64-apple-darwin".into())
579+
.build()
580+
.expect("failed to build settings");
581+
582+
let bundle_dir = project_dir.join("TestApp.app/Contents");
583+
fs::create_dir_all(&bundle_dir).expect("failed to create bundle dir");
584+
585+
(bundle_dir, settings)
586+
}
587+
588+
#[test]
589+
fn test_copy_custom_file_to_bundle_file() {
590+
let tmp_dir = tempfile::tempdir().expect("failed to create temp dir");
591+
592+
// Prepare a single file to copy.
593+
let src_file = tmp_dir.path().join("sample.txt");
594+
fs::write(&src_file, b"hello tauri").expect("failed to write sample file");
595+
596+
let files_map = HashMap::from([(PathBuf::from("Resources/sample.txt"), src_file.clone())]);
597+
598+
let (bundle_dir, settings) = create_test_bundle(tmp_dir.path(), files_map);
599+
600+
copy_custom_files_to_bundle(&bundle_dir, &settings)
601+
.expect("copy_custom_files_to_bundle failed");
602+
603+
let dest_file = bundle_dir.join("Resources/sample.txt");
604+
assert!(dest_file.exists() && dest_file.is_file());
605+
assert_eq!(fs::read_to_string(dest_file).unwrap(), "hello tauri");
606+
}
607+
608+
#[test]
609+
fn test_copy_custom_file_to_bundle_dir() {
610+
let tmp_dir = tempfile::tempdir().expect("failed to create temp dir");
611+
612+
// Create a source directory with a nested file.
613+
let src_dir = tmp_dir.path().join("assets");
614+
fs::create_dir_all(&src_dir).expect("failed to create assets directory");
615+
let nested_file = src_dir.join("nested.txt");
616+
fs::write(&nested_file, b"nested").expect("failed to write nested file");
617+
618+
let files_map = HashMap::from([(PathBuf::from("MyAssets"), src_dir.clone())]);
619+
620+
let (bundle_dir, settings) = create_test_bundle(tmp_dir.path(), files_map);
621+
622+
copy_custom_files_to_bundle(&bundle_dir, &settings)
623+
.expect("copy_custom_files_to_bundle failed");
624+
625+
let dest_nested_file = bundle_dir.join("MyAssets/nested.txt");
626+
assert!(
627+
dest_nested_file.exists(),
628+
"{dest_nested_file:?} does not exist"
629+
);
630+
assert!(
631+
dest_nested_file.is_file(),
632+
"{dest_nested_file:?} is not a file"
633+
);
634+
assert_eq!(
635+
fs::read_to_string(dest_nested_file).unwrap().trim(),
636+
"nested"
637+
);
638+
}
639+
640+
#[test]
641+
fn test_copy_custom_files_to_bundle_missing_source() {
642+
let tmp_dir = tempfile::tempdir().expect("failed to create temp dir");
643+
644+
// Intentionally reference a non-existent path.
645+
let missing_path = tmp_dir.path().join("does_not_exist.txt");
646+
647+
let files_map = HashMap::from([(PathBuf::from("Missing.txt"), missing_path)]);
648+
649+
let (bundle_dir, settings) = create_test_bundle(tmp_dir.path(), files_map);
650+
651+
let result = copy_custom_files_to_bundle(&bundle_dir, &settings);
652+
653+
assert!(result.is_err());
654+
assert!(result.err().unwrap().to_string().contains("does not exist"));
655+
}
656+
657+
#[test]
658+
fn test_copy_custom_files_to_bundle_invalid_source() {
659+
let tmp_dir = tempfile::tempdir().expect("failed to create temp dir");
660+
661+
let files_map = HashMap::from([(PathBuf::from("Invalid.txt"), PathBuf::from("///"))]);
662+
663+
let (bundle_dir, settings) = create_test_bundle(tmp_dir.path(), files_map);
664+
665+
let result = copy_custom_files_to_bundle(&bundle_dir, &settings);
666+
assert!(result.is_err());
667+
assert!(result
668+
.err()
669+
.unwrap()
670+
.to_string()
671+
.contains("Failed to copy directory"));
672+
}
673+
674+
#[test]
675+
fn test_copy_custom_files_to_bundle_dev_null() {
676+
let tmp_dir = tempfile::tempdir().expect("failed to create temp dir");
677+
678+
let files_map = HashMap::from([(PathBuf::from("Invalid.txt"), PathBuf::from("/dev/null"))]);
679+
680+
let (bundle_dir, settings) = create_test_bundle(tmp_dir.path(), files_map);
681+
682+
let result = copy_custom_files_to_bundle(&bundle_dir, &settings);
683+
assert!(result.is_err());
684+
assert!(result
685+
.err()
686+
.unwrap()
687+
.to_string()
688+
.contains("is not a file or directory."));
689+
}
690+
}

0 commit comments

Comments
 (0)