diff --git a/CHANGELOG.md b/CHANGELOG.md index c7db31d4..8fbb0cac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.10.4](https://github.com/rash-sh/rash/tree/v1.10.4) - 2024-07-04 + +### Build + +- deps: Update Rust crate serde_json to v1.0.118 +- deps: Update Rust crate log to v0.4.22 +- deps: Update Rust crate clap to v4.5.8 +- deps: Update Rust crate serde_json to v1.0.119 +- deps: Update Rust crate serde_with to v3.8.2 +- deps: Update Rust crate serde_json to v1.0.120 +- deps: Update KSXGitHub/github-actions-deploy-aur action to v2.7.2 +- deps: Update Rust crate serde_with to v3.8.3 + +### Fixed + +- module: Copy binary data + ## [v1.10.3](https://github.com/rash-sh/rash/tree/v1.10.3) - 2024-06-24 ### Build diff --git a/Cargo.lock b/Cargo.lock index 54c44538..455e6d8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1047,7 +1047,7 @@ dependencies = [ [[package]] name = "mdbook_rash" -version = "1.10.3" +version = "1.10.4" dependencies = [ "chrono", "clap", @@ -1373,7 +1373,7 @@ dependencies = [ [[package]] name = "rash_core" -version = "1.10.3" +version = "1.10.4" dependencies = [ "byte-unit", "cargo-husky", @@ -1407,7 +1407,7 @@ dependencies = [ [[package]] name = "rash_derive" -version = "1.10.3" +version = "1.10.4" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index a450e39a..1fee90e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ resolver = "2" [workspace.package] -version = "1.10.3" +version = "1.10.4" authors = ["Pando85 "] rust-version = "1.74" edition = "2021" diff --git a/mdbook_rash/Cargo.toml b/mdbook_rash/Cargo.toml index 22fd3cf5..b8cacbce 100644 --- a/mdbook_rash/Cargo.toml +++ b/mdbook_rash/Cargo.toml @@ -15,7 +15,7 @@ path = "src/bin/mdbook-rash.rs" doc = false [dependencies] -rash_core = { path = "../rash_core", features = ["docs"], version = "1.10.3" } +rash_core = { path = "../rash_core", features = ["docs"], version = "1.10.4" } lazy_static.workspace = true log.workspace = true regex.workspace = true diff --git a/rash_core/Cargo.toml b/rash_core/Cargo.toml index 3ca5e7db..7ddfb1cc 100644 --- a/rash_core/Cargo.toml +++ b/rash_core/Cargo.toml @@ -21,7 +21,7 @@ path = "src/bin/rash.rs" docs = ["rash_derive/docs", "schemars"] [dependencies] -rash_derive = { path = "../rash_derive", version = "1.10.3" } +rash_derive = { path = "../rash_derive", version = "1.10.4" } lazy_static.workspace = true log.workspace = true regex.workspace = true diff --git a/rash_core/src/modules/copy.rs b/rash_core/src/modules/copy.rs index 77852564..d9401c88 100644 --- a/rash_core/src/modules/copy.rs +++ b/rash_core/src/modules/copy.rs @@ -32,6 +32,8 @@ use rash_derive::DocJsonSchema; use std::fs::{metadata, set_permissions, File, OpenOptions, Permissions}; use std::io::prelude::*; +use std::fmt; +use std::io::Result as IoResult; use std::io::{BufReader, Write}; use std::os::unix::fs::PermissionsExt; @@ -97,6 +99,48 @@ fn change_permissions( Ok(false) } +#[derive(Debug, PartialEq)] +enum Content { + Str(String), + Bytes(Vec), +} + +// Implement std::fmt::Display for Content +impl fmt::Display for Content { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Content::Str(s) => write!(f, "{}", s), + Content::Bytes(b) => write!(f, "{:?}", b), + } + } +} + +impl Content { + fn as_bytes(&self) -> &[u8] { + match self { + Content::Str(s) => s.as_bytes(), + Content::Bytes(b) => b, + } + } + + fn len(&self) -> usize { + match self { + Content::Str(s) => s.len(), + Content::Bytes(b) => b.len(), + } + } +} + +fn read_content(buf_reader: &mut R) -> IoResult { + let mut content = Vec::new(); + buf_reader.read_to_end(&mut content)?; + + match String::from_utf8(content.clone()) { + Ok(s) => Ok(Content::Str(s)), + Err(_) => Ok(Content::Bytes(content)), + } +} + pub fn copy_file(params: Params, check_mode: bool) -> Result { trace!("params: {:?}", params); let open_read_file = OpenOptions::new().read(true).clone(); @@ -114,20 +158,17 @@ pub fn copy_file(params: Params, check_mode: bool) -> Result { } })?; let mut buf_reader = BufReader::new(&read_file); - let mut content = String::new(); - buf_reader.read_to_string(&mut content)?; + let content = read_content(&mut buf_reader)?; let dest_metadata = read_file.metadata()?; let dest_permissions = dest_metadata.permissions(); let mut changed = false; let desired_content = match params.input.clone() { - Input::Content(s) => s, + Input::Content(s) => Content::Str(s), Input::Src(src) => { let file = File::open(src)?; let mut buf_reader = BufReader::new(file); - let mut contents = String::new(); - buf_reader.read_to_string(&mut contents)?; - contents + read_content(&mut buf_reader)? } }; @@ -876,4 +917,51 @@ mod tests { } ); } + + #[test] + fn test_copy_file_binary() { + let dir = tempdir().unwrap(); + + let src_path = dir.path().join("image.png"); + let file_path = dir.path().join("output_image.png"); + + let image_data: &[u8] = &[ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, + 0x44, 0x52, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x08, 0x06, 0x00, 0x00, + 0x00, 0x8d, 0x6f, 0x26, 0xe5, 0x00, 0x00, 0x00, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x08, + 0xd7, 0x63, 0xf8, + ]; + let mut file = File::create(src_path.clone()).unwrap(); + file.write_all(image_data).unwrap(); + let output = copy_file( + Params { + input: Input::Src(src_path.into_os_string().into_string().unwrap()), + dest: file_path.to_str().unwrap().to_owned(), + mode: Some("0400".to_owned()), + }, + false, + ) + .unwrap(); + + let mut file = File::open(&file_path).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(contents, image_data); + + let metadata = file.metadata().unwrap(); + let permissions = metadata.permissions(); + assert_eq!( + format!("{:o}", permissions.mode() & 0o7777), + format!("{:o}", 0o400) + ); + + assert_eq!( + output, + ModuleResult { + changed: true, + output: Some(file_path.to_str().unwrap().to_owned()), + extra: None, + } + ); + } }