implement argument option to Keep Nex entry on Snac post was removed (disables cleanup action)

This commit is contained in:
postscriptum 2025-07-03 12:30:51 +03:00
parent 499a78004a
commit d8dac50cb6
5 changed files with 66 additions and 24 deletions

View file

@ -35,9 +35,7 @@ snac2nex -s /path/to/snac/storage -t /path/to/nex -u user1 -u user2
Supported values: Supported values:
* `c` (`copy`) - copy files * `c` (`copy`) - copy files * `h` (`hard`) - create hard links * `s` (`soft`) - create soft links (macos, linux, windows only)
* `h` (`hard`) - create hard links
* `s` (`soft`) - create soft links (macos, linux, windows only)
-r, --rotate <ROTATE> -r, --rotate <ROTATE>
Keep running as the daemon, renew every `n` seconds Keep running as the daemon, renew every `n` seconds
@ -61,6 +59,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"]
-k, --keep
Keep Nex entry on Snac post was removed
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')

View file

@ -44,4 +44,8 @@ pub struct Config {
/// * escaped with `%%` /// * escaped with `%%`
#[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,
/// Keep Nex entry on Snac post was removed
#[arg(short, long, default_value_t = false)]
pub keep: bool,
} }

View file

@ -19,6 +19,7 @@ fn main() -> Result<()> {
c.format_updated, c.format_updated,
c.format_content, c.format_content,
c.attachment, c.attachment,
!c.keep,
&c.user, &c.user,
)?; )?;
let s = Snac::init(c.source, c.user)?; let s = Snac::init(c.source, c.user)?;
@ -48,7 +49,11 @@ fn sync(snac: &Snac, nex: &Nex) -> Result<Response> {
let mut r = Response::default(); let mut r = Response::default();
for user in &snac.users { for user in &snac.users {
println!("\tsync profile for `{}`...", user.name); println!("\tsync profile for `{}`...", user.name);
let mut keep = HashSet::with_capacity(100); // @TODO estimated let mut keep = if nex.is_cleanup() {
Some(HashSet::with_capacity(100)) // @TODO estimated
} else {
None
};
for post in user.public()? { for post in user.public()? {
r.total += 1; r.total += 1;
// make sure post entry has expected content type // make sure post entry has expected content type
@ -106,15 +111,21 @@ fn sync(snac: &Snac, nex: &Nex) -> Result<Response> {
println!("\t\t\tpost file `{f}` update with new content.") println!("\t\t\tpost file `{f}` update with new content.")
} }
} }
for i in response.keep { if let Some(ref mut k) = keep
keep.insert(i); && let Some(r) = response.keep
{
for i in r {
k.insert(i);
}
} }
} }
} }
// cleanup removed post entries // cleanup removed post entries
let d = nex.clean(&user.name, keep)?; if let Some(k) = keep {
r.deleted.directories += d.directories; let d = nex.clean(&user.name, k)?;
r.deleted.files += d.files; r.deleted.directories += d.directories;
r.deleted.files += d.files;
}
} }
Ok(r) Ok(r)
} }

View file

@ -17,6 +17,7 @@ use std::{
pub struct Nex { pub struct Nex {
attachment: Attachment, attachment: Attachment,
filename: String, filename: String,
is_cleanup: bool,
pattern: String, pattern: String,
time_format: String, time_format: String,
users: HashMap<String, PathBuf>, users: HashMap<String, PathBuf>,
@ -29,6 +30,7 @@ impl Nex {
time_format: String, time_format: String,
pattern: String, pattern: String,
attachment_mode: Option<String>, attachment_mode: Option<String>,
is_cleanup: bool,
user_names: &Vec<String>, user_names: &Vec<String>,
) -> Result<Self> { ) -> Result<Self> {
use std::path::MAIN_SEPARATOR; use std::path::MAIN_SEPARATOR;
@ -52,16 +54,15 @@ impl Nex {
Ok(Self { Ok(Self {
attachment: Attachment::init(attachment_mode)?, attachment: Attachment::init(attachment_mode)?,
filename, filename,
is_cleanup,
pattern, pattern,
time_format, time_format,
users, users,
}) })
} }
// @TODO: This function requires the following improvements: // Sync the Snac post with the Nex entry
// * validate attachments before updating // * @TODO apply the post time to the files
// * apply the post time to the files
/// Update destination with given data (typically received from Snac)
pub fn sync( pub fn sync(
&self, &self,
name: &str, name: &str,
@ -72,21 +73,33 @@ impl Nex {
(published, updated): (DateTime<Utc>, Option<DateTime<Utc>>), (published, updated): (DateTime<Utc>, Option<DateTime<Utc>>),
) -> Result<Sync> { ) -> Result<Sync> {
// collect existing entries to ignore on cleanup // collect existing entries to ignore on cleanup
let mut i = Vec::with_capacity(10); // includes est. attachments len let mut index = if self.is_cleanup {
Some(Vec::with_capacity(10)) // includes est. attachments len
} else {
None
};
// prepare destination // prepare destination
let root = PathBuf::from(self.users.get(name).unwrap()); let root = PathBuf::from(self.users.get(name).unwrap());
let mut p = PathBuf::from(&root); let mut p = PathBuf::from(&root);
i.push(root); if let Some(ref mut i) = index {
i.push(root);
}
p.push(published.format("%Y").to_string()); p.push(published.format("%Y").to_string());
i.push(p.clone()); if let Some(ref mut i) = index {
i.push(p.clone());
}
p.push(published.format("%m").to_string()); p.push(published.format("%m").to_string());
i.push(p.clone()); if let Some(ref mut i) = index {
i.push(p.clone());
}
p.push(published.format("%d").to_string()); p.push(published.format("%d").to_string());
i.push(p.clone()); if let Some(ref mut i) = index {
i.push(p.clone());
}
fs::create_dir_all(&p)?; fs::create_dir_all(&p)?;
@ -114,10 +127,12 @@ impl Nex {
fs::create_dir_all(&d)?; fs::create_dir_all(&d)?;
fs::write(&s, updated.unwrap_or(published).to_string())? fs::write(&s, updated.unwrap_or(published).to_string())?
} else { } else {
i.extend([d, f, p, s]); // move all paths processed to cleanup ignore if let Some(ref mut i) = index {
i.extend([d, f, p, s]);
}
return Ok(Sync { return Ok(Sync {
change: Change::Ignored, change: Change::Ignored,
keep: i, keep: index,
}); });
} }
@ -157,7 +172,9 @@ impl Nex {
if !to.exists() { if !to.exists() {
self.attachment.sync(&from, &to).unwrap() self.attachment.sync(&from, &to).unwrap()
} }
i.push(to); if let Some(ref mut i) = index {
i.push(to);
}
format!("{}/{f}", d.file_name().unwrap().to_string_lossy()) format!("{}/{f}", d.file_name().unwrap().to_string_lossy())
} }
} }
@ -197,9 +214,14 @@ impl Nex {
fs::write(&f, c)?; fs::write(&f, c)?;
// move all paths processed to cleanup ignore // move all paths processed to cleanup ignore
i.extend([d, f, p, s]); if let Some(ref mut i) = index {
i.extend([d, f, p, s]);
}
Ok(Sync { change, keep: i }) Ok(Sync {
change,
keep: index,
})
} }
pub fn clean(&self, name: &str, ignore: HashSet<PathBuf>) -> Result<Clean> { pub fn clean(&self, name: &str, ignore: HashSet<PathBuf>) -> Result<Clean> {
@ -233,4 +255,8 @@ impl Nex {
pub fn is_attachments_disabled(&self) -> bool { pub fn is_attachments_disabled(&self) -> bool {
matches!(self.attachment, Attachment::Disabled) matches!(self.attachment, Attachment::Disabled)
} }
pub fn is_cleanup(&self) -> bool {
self.is_cleanup
}
} }

View file

@ -2,7 +2,7 @@ pub mod change;
pub struct Sync { pub struct Sync {
pub change: change::Change, pub change: change::Change,
pub keep: Vec<std::path::PathBuf>, pub keep: Option<Vec<std::path::PathBuf>>,
} }
#[derive(Default)] #[derive(Default)]