diff --git a/README.md b/README.md index 39ea6a7..5f7c18d 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ snac2nex -s /path/to/snac/storage -t /path/to/nex -u user1 -u user2 [default: "%Y/%m/%d %H:%M:%S"] + --filesystem-sync + Sync filesystem meta (e.g. time modified) + -k, --keep Keep Nex entry on Snac post was removed diff --git a/src/config.rs b/src/config.rs index 370595c..a171107 100644 --- a/src/config.rs +++ b/src/config.rs @@ -48,6 +48,10 @@ pub struct Config { #[arg(long, default_value_t = String::from("%Y/%m/%d %H:%M:%S"))] pub format_updated: String, + /// Sync filesystem meta (e.g. time modified) + #[arg(long, default_value_t = false)] + pub filesystem_sync: bool, + /* @TODO /// Set directory permissions (macos, linux only) #[arg(long, value_parser = chmod, default_value_t = 0o755)] diff --git a/src/main.rs b/src/main.rs index 520c9ea..a4b95f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ fn main() -> Result<()> { c.format_updated, c.format_content, c.attachment, - (!c.keep, !c.daemon), + (!c.keep, !c.daemon, c.filesystem_sync), &c.user, )?; let s = Snac::init(c.source, c.user)?; diff --git a/src/nex.rs b/src/nex.rs index cd2146c..713950e 100644 --- a/src/nex.rs +++ b/src/nex.rs @@ -21,6 +21,7 @@ pub struct Nex { filename: String, is_cleanup: bool, is_debug: bool, + is_filesystem_sync: bool, template: Template, users: HashMap, } @@ -32,7 +33,7 @@ impl Nex { time_format: String, pattern: String, attachment_mode: Option, - (is_cleanup, is_debug): (bool, bool), + (is_cleanup, is_debug, is_filesystem_sync): (bool, bool, bool), user_names: &Vec, ) -> Result { // validate filename @@ -61,9 +62,10 @@ impl Nex { Ok(Self { attachment: Attachment::init(attachment_mode)?, filename, - template, is_cleanup, is_debug, + is_filesystem_sync, + template, users, }) } @@ -134,7 +136,11 @@ impl Nex { if !fs::read_to_string(&s).is_ok_and(|this| this == state) { fs::remove_dir_all(&d)?; fs::create_dir_all(&d)?; - save(&s, timestamp.into(), state.as_bytes())? + if self.is_filesystem_sync { + sync(&s, timestamp.into(), state.as_bytes())? + } else { + fs::write(&s, state)? + } } else { if let Some(ref mut i) = index { if let Some(ref a) = attachments { @@ -159,57 +165,65 @@ impl Nex { } else { Change::Created }; - save( - &f, - timestamp.into(), - self.template - .build( - updated, - content, - link, - tags, - attachments.map(|a| { - let mut b = Vec::with_capacity(a.len()); - for (n, (name, media_type, source)) in a.into_iter().enumerate() { - b.push(( - match source { - Source::Url(url) => url, - Source::File(from) => { - let to = attachment::filepath(&d, &from, n); - let uri = format!( - "{}/{}", - d.file_name().unwrap().to_string_lossy(), - to.file_name().unwrap().to_string_lossy() - ); - self.attachment.sync(&from, &to, timestamp.into()).unwrap(); - if let Some(ref mut i) = index { - i.push(to); - } - uri - } - }, - { - let mut alt = Vec::with_capacity(2); - if !name.is_empty() { - alt.push(name) - } - if !media_type.is_empty() { - alt.push(format!("({media_type})")) - } - if alt.is_empty() { - None - } else { - Some(alt.join(" ")) - } - }, - )) - } - b - }), - ) - .as_bytes(), - )?; - + let template = self.template.build( + updated, + content, + link, + tags, + attachments.map(|a| { + let mut b = Vec::with_capacity(a.len()); + for (n, (name, media_type, source)) in a.into_iter().enumerate() { + b.push(( + match source { + Source::Url(url) => url, + Source::File(from) => { + let to = attachment::filepath(&d, &from, n); + let uri = format!( + "{}/{}", + d.file_name().unwrap().to_string_lossy(), + to.file_name().unwrap().to_string_lossy() + ); + self.attachment + .sync( + &from, + &to, + if self.is_filesystem_sync { + Some(timestamp.into()) + } else { + None + }, + ) + .unwrap(); + if let Some(ref mut i) = index { + i.push(to); + } + uri + } + }, + { + let mut alt = Vec::with_capacity(2); + if !name.is_empty() { + alt.push(name) + } + if !media_type.is_empty() { + alt.push(format!("({media_type})")) + } + if alt.is_empty() { + None + } else { + Some(alt.join(" ")) + } + }, + )) + } + b + }), + ); + if self.is_filesystem_sync { + sync(&f, timestamp.into(), template.as_bytes())? + } else { + fs::write(&f, template)? + } // move all paths processed to cleanup ignore if let Some(ref mut i) = index { i.extend([d, f, p, s]); @@ -268,7 +282,7 @@ impl Nex { } /// Wrapper function to change time updated for new file, according to the Snac time. -fn save(path: &PathBuf, modified: std::time::SystemTime, data: &[u8]) -> Result<()> { +fn sync(path: &PathBuf, modified: std::time::SystemTime, data: &[u8]) -> Result<()> { use std::io::Write; let mut f = fs::File::create(path)?; f.write_all(data)?; diff --git a/src/nex/attachment.rs b/src/nex/attachment.rs index 47c7d83..ef838e8 100644 --- a/src/nex/attachment.rs +++ b/src/nex/attachment.rs @@ -23,12 +23,16 @@ impl Attachment { None => Self::Disabled, }) } - pub fn sync(&self, source: &PathBuf, target: &PathBuf, modified: SystemTime) -> Result<()> { + pub fn sync( + &self, + source: &PathBuf, + target: &PathBuf, + modified: Option, + ) -> Result<()> { use std::{fs, os}; match self { Attachment::Copy => { fs::copy(source, target)?; - fs::File::open(target)?.set_modified(modified)?; #[cfg(any(target_os = "linux", target_os = "macos"))] { use std::{fs::Permissions, os::unix::fs::PermissionsExt}; @@ -72,6 +76,9 @@ impl Attachment { } _ => panic!(), // warn as unexpected } + if let Some(t) = modified { + fs::File::open(target)?.set_modified(t)? + } Ok(()) } }