implement filesystem_sync option

This commit is contained in:
postscriptum 2025-07-05 15:14:04 +03:00
parent c2d8336156
commit 0862525811
5 changed files with 86 additions and 58 deletions

View file

@ -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"] [default: "%Y/%m/%d %H:%M:%S"]
--filesystem-sync
Sync filesystem meta (e.g. time modified)
-k, --keep -k, --keep
Keep Nex entry on Snac post was removed Keep Nex entry on Snac post was removed

View file

@ -48,6 +48,10 @@ pub struct Config {
#[arg(long, default_value_t = String::from("%Y/%m/%d %H:%M:%S"))] #[arg(long, default_value_t = String::from("%Y/%m/%d %H:%M:%S"))]
pub format_updated: String, pub format_updated: String,
/// Sync filesystem meta (e.g. time modified)
#[arg(long, default_value_t = false)]
pub filesystem_sync: bool,
/* @TODO /* @TODO
/// Set directory permissions (macos, linux only) /// Set directory permissions (macos, linux only)
#[arg(long, value_parser = chmod, default_value_t = 0o755)] #[arg(long, value_parser = chmod, default_value_t = 0o755)]

View file

@ -21,7 +21,7 @@ fn main() -> Result<()> {
c.format_updated, c.format_updated,
c.format_content, c.format_content,
c.attachment, c.attachment,
(!c.keep, !c.daemon), (!c.keep, !c.daemon, c.filesystem_sync),
&c.user, &c.user,
)?; )?;
let s = Snac::init(c.source, c.user)?; let s = Snac::init(c.source, c.user)?;

View file

@ -21,6 +21,7 @@ pub struct Nex {
filename: String, filename: String,
is_cleanup: bool, is_cleanup: bool,
is_debug: bool, is_debug: bool,
is_filesystem_sync: bool,
template: Template, template: Template,
users: HashMap<String, PathBuf>, users: HashMap<String, PathBuf>,
} }
@ -32,7 +33,7 @@ impl Nex {
time_format: String, time_format: String,
pattern: String, pattern: String,
attachment_mode: Option<String>, attachment_mode: Option<String>,
(is_cleanup, is_debug): (bool, bool), (is_cleanup, is_debug, is_filesystem_sync): (bool, bool, bool),
user_names: &Vec<String>, user_names: &Vec<String>,
) -> Result<Self> { ) -> Result<Self> {
// validate filename // validate filename
@ -61,9 +62,10 @@ impl Nex {
Ok(Self { Ok(Self {
attachment: Attachment::init(attachment_mode)?, attachment: Attachment::init(attachment_mode)?,
filename, filename,
template,
is_cleanup, is_cleanup,
is_debug, is_debug,
is_filesystem_sync,
template,
users, users,
}) })
} }
@ -134,7 +136,11 @@ impl Nex {
if !fs::read_to_string(&s).is_ok_and(|this| this == state) { if !fs::read_to_string(&s).is_ok_and(|this| this == state) {
fs::remove_dir_all(&d)?; fs::remove_dir_all(&d)?;
fs::create_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 { } else {
if let Some(ref mut i) = index { if let Some(ref mut i) = index {
if let Some(ref a) = attachments { if let Some(ref a) = attachments {
@ -159,57 +165,65 @@ impl Nex {
} else { } else {
Change::Created Change::Created
}; };
save( let template = self.template.build(
&f, updated,
timestamp.into(), content,
self.template link,
.build( tags,
updated, attachments.map(|a| {
content, let mut b = Vec::with_capacity(a.len());
link, for (n, (name, media_type, source)) in a.into_iter().enumerate() {
tags, b.push((
attachments.map(|a| { match source {
let mut b = Vec::with_capacity(a.len()); Source::Url(url) => url,
for (n, (name, media_type, source)) in a.into_iter().enumerate() { Source::File(from) => {
b.push(( let to = attachment::filepath(&d, &from, n);
match source { let uri = format!(
Source::Url(url) => url, "{}/{}",
Source::File(from) => { d.file_name().unwrap().to_string_lossy(),
let to = attachment::filepath(&d, &from, n); to.file_name().unwrap().to_string_lossy()
let uri = format!( );
"{}/{}", self.attachment
d.file_name().unwrap().to_string_lossy(), .sync(
to.file_name().unwrap().to_string_lossy() &from,
); &to,
self.attachment.sync(&from, &to, timestamp.into()).unwrap(); if self.is_filesystem_sync {
if let Some(ref mut i) = index { Some(timestamp.into())
i.push(to); } else {
} None
uri },
} )
}, .unwrap();
{ if let Some(ref mut i) = index {
let mut alt = Vec::with_capacity(2); i.push(to);
if !name.is_empty() { }
alt.push(name) uri
} }
if !media_type.is_empty() { },
alt.push(format!("({media_type})")) {
} let mut alt = Vec::with_capacity(2);
if alt.is_empty() { if !name.is_empty() {
None alt.push(name)
} else { }
Some(alt.join(" ")) if !media_type.is_empty() {
} alt.push(format!("({media_type})"))
}, }
)) if alt.is_empty() {
} None
b } else {
}), Some(alt.join(" "))
) }
.as_bytes(), },
)?; ))
}
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 // move all paths processed to cleanup ignore
if let Some(ref mut i) = index { if let Some(ref mut i) = index {
i.extend([d, f, p, s]); 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. /// 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; use std::io::Write;
let mut f = fs::File::create(path)?; let mut f = fs::File::create(path)?;
f.write_all(data)?; f.write_all(data)?;

View file

@ -23,12 +23,16 @@ impl Attachment {
None => Self::Disabled, None => Self::Disabled,
}) })
} }
pub fn sync(&self, source: &PathBuf, target: &PathBuf, modified: SystemTime) -> Result<()> { pub fn sync(
&self,
source: &PathBuf,
target: &PathBuf,
modified: Option<SystemTime>,
) -> Result<()> {
use std::{fs, os}; use std::{fs, os};
match self { match self {
Attachment::Copy => { Attachment::Copy => {
fs::copy(source, target)?; fs::copy(source, target)?;
fs::File::open(target)?.set_modified(modified)?;
#[cfg(any(target_os = "linux", target_os = "macos"))] #[cfg(any(target_os = "linux", target_os = "macos"))]
{ {
use std::{fs::Permissions, os::unix::fs::PermissionsExt}; use std::{fs::Permissions, os::unix::fs::PermissionsExt};
@ -72,6 +76,9 @@ impl Attachment {
} }
_ => panic!(), // warn as unexpected _ => panic!(), // warn as unexpected
} }
if let Some(t) = modified {
fs::File::open(target)?.set_modified(t)?
}
Ok(()) Ok(())
} }
} }