diff --git a/src/os/fs.rs b/src/os/fs.rs index 26f374c..ef174bf 100644 --- a/src/os/fs.rs +++ b/src/os/fs.rs @@ -6,6 +6,8 @@ use std::path::Path; use std::process::Command; use libc; use dirs; +#[cfg(not(target_os = "windows"))] +use std::os::unix::fs::PermissionsExt; // Define a custom error type for file system operations #[derive(Debug)] @@ -77,39 +79,14 @@ impl Error for FsError { } } -/** - * Recursively copy a file or directory from source to destination. - * - * # Arguments - * - * * `src` - The source path, which can include wildcards - * * `dest` - The destination path - * - * # Returns - * - * * `Ok(String)` - A success message indicating what was copied - * * `Err(FsError)` - An error if the copy operation failed - * - * # Examples - * - * ```no_run - * use sal::os::copy; - * - * fn main() -> Result<(), Box> { - * // Copy a single file - * let result = copy("file.txt", "backup/file.txt")?; - * - * // Copy multiple files using wildcards - * let result = copy("*.txt", "backup/")?; - * - * // Copy a directory recursively - * let result = copy("src_dir", "dest_dir")?; - * - * Ok(()) - * } - * ``` - */ -pub fn copy(src: &str, dest: &str) -> Result { +#[cfg(not(target_os = "windows"))] +fn set_executable(path: &Path) -> Result<(), io::Error> { + let mut perms = fs::metadata(path)?.permissions(); + perms.set_mode(0o755); // rwxr-xr-x + fs::set_permissions(path, perms) +} + +fn copy_internal(src: &str, dest: &str, make_executable: bool) -> Result { let dest_path = Path::new(dest); // Check if source path contains wildcards @@ -155,6 +132,18 @@ pub fn copy(src: &str, dest: &str) -> Result { println!("Warning: Failed to copy {}: {}", path.display(), e); } else { success_count += 1; + if make_executable { + #[cfg(not(target_os = "windows"))] + { + if let Err(e) = set_executable(&target_path) { + println!( + "Warning: Failed to make {} executable: {}", + target_path.display(), + e + ); + } + } + } } } else if path.is_dir() { // For directories, use platform-specific command @@ -225,7 +214,19 @@ pub fn copy(src: &str, dest: &str) -> Result { if dest_path.exists() && dest_path.is_dir() { let file_name = src_path.file_name().unwrap_or_default(); let new_dest_path = dest_path.join(file_name); - fs::copy(src_path, new_dest_path).map_err(FsError::CopyFailed)?; + fs::copy(src_path, &new_dest_path).map_err(FsError::CopyFailed)?; + if make_executable { + #[cfg(not(target_os = "windows"))] + { + if let Err(e) = set_executable(&new_dest_path) { + println!( + "Warning: Failed to make {} executable: {}", + new_dest_path.display(), + e + ); + } + } + } Ok(format!( "Successfully copied file '{}' to '{}/{}'", src, @@ -235,6 +236,18 @@ pub fn copy(src: &str, dest: &str) -> Result { } else { // Otherwise copy file to the specified destination fs::copy(src_path, dest_path).map_err(FsError::CopyFailed)?; + if make_executable { + #[cfg(not(target_os = "windows"))] + { + if let Err(e) = set_executable(dest_path) { + println!( + "Warning: Failed to make {} executable: {}", + dest_path.display(), + e + ); + } + } + } Ok(format!("Successfully copied file '{}' to '{}'", src, dest)) } } else if src_path.is_dir() { @@ -269,6 +282,43 @@ pub fn copy(src: &str, dest: &str) -> Result { } } } + +/** + * Recursively copy a file or directory from source to destination. + * + * # Arguments + * + * * `src` - The source path, which can include wildcards + * * `dest` - The destination path + * + * # Returns + * + * * `Ok(String)` - A success message indicating what was copied + * * `Err(FsError)` - An error if the copy operation failed + * + * # Examples + * + * ```no_run + * use sal::os::copy; + * + * fn main() -> Result<(), Box> { + * // Copy a single file + * let result = copy("file.txt", "backup/file.txt")?; + * + * // Copy multiple files using wildcards + * let result = copy("*.txt", "backup/")?; + * + * // Copy a directory recursively + * let result = copy("src_dir", "dest_dir")?; + * + * Ok(()) + * } + * ``` + */ +pub fn copy(src: &str, dest: &str) -> Result { + copy_internal(src, dest, false) +} + /** * Copy a binary to the correct location based on OS and user privileges. * @@ -302,7 +352,7 @@ pub fn copy_bin(src: &str) -> Result { .join("hero/bin") }; - let result = copy(src, dest_path.to_str().unwrap()); + let result = copy_internal(src, dest_path.to_str().unwrap(), true); if let Ok(msg) = &result { println!("{}", msg); }