refactor(cli): move trash family (rm/restore/purge/trash) into commands/
This commit is contained in:
@@ -13,6 +13,7 @@ pub mod list;
|
||||
pub mod rate;
|
||||
pub mod status;
|
||||
pub mod sync;
|
||||
pub mod trash;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
|
||||
132
crates/relicario-cli/src/commands/trash.rs
Normal file
132
crates/relicario-cli/src/commands/trash.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
//! Trash umbrella: `rm` (soft-delete), `restore`, `purge` (permanent),
|
||||
//! `trash list` / `trash empty`.
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::TrashAction;
|
||||
|
||||
pub fn cmd_rm(query: String) -> Result<()> {
|
||||
let vault = crate::session::UnlockedVault::unlock_interactive()?;
|
||||
let mut manifest = vault.load_manifest()?;
|
||||
let entry = super::resolve_query(&manifest, &query)?;
|
||||
let id = entry.id.clone();
|
||||
let _ = entry;
|
||||
let mut item = vault.load_item(&id)?;
|
||||
item.soft_delete();
|
||||
vault.save_item(&item)?;
|
||||
manifest.upsert(&item);
|
||||
vault.save_manifest(&manifest)?;
|
||||
crate::refresh_groups_cache(vault.root(), &manifest);
|
||||
super::commit_paths(&vault, &format!("trash: {} ({})", crate::helpers::sanitize_for_commit(&item.title), item.id.as_str()),
|
||||
&[&format!("items/{}.enc", item.id.as_str()), "manifest.enc"])?;
|
||||
eprintln!("Moved to trash: {}", item.title);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_restore(query: String) -> Result<()> {
|
||||
let vault = crate::session::UnlockedVault::unlock_interactive()?;
|
||||
let mut manifest = vault.load_manifest()?;
|
||||
let entry = super::resolve_query(&manifest, &query)?;
|
||||
let id = entry.id.clone();
|
||||
let _ = entry;
|
||||
let mut item = vault.load_item(&id)?;
|
||||
item.restore();
|
||||
vault.save_item(&item)?;
|
||||
manifest.upsert(&item);
|
||||
vault.save_manifest(&manifest)?;
|
||||
crate::refresh_groups_cache(vault.root(), &manifest);
|
||||
super::commit_paths(&vault, &format!("restore: {} ({})", crate::helpers::sanitize_for_commit(&item.title), item.id.as_str()),
|
||||
&[&format!("items/{}.enc", item.id.as_str()), "manifest.enc"])?;
|
||||
eprintln!("Restored: {}", item.title);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inner purge: assumes vault is already unlocked and manifest is loaded.
|
||||
/// Caller is responsible for saving the manifest and committing afterwards.
|
||||
pub(super) fn purge_item(
|
||||
vault: &crate::session::UnlockedVault,
|
||||
manifest: &mut relicario_core::Manifest,
|
||||
id: &relicario_core::ItemId,
|
||||
title: &str,
|
||||
) -> Result<()> {
|
||||
use std::fs;
|
||||
|
||||
let item_path = vault.item_path(id);
|
||||
if item_path.exists() { fs::remove_file(&item_path)?; }
|
||||
let att_dir = vault.root().join("attachments").join(id.as_str());
|
||||
if att_dir.exists() { fs::remove_dir_all(&att_dir)?; }
|
||||
manifest.remove(id);
|
||||
|
||||
let _ = crate::helpers::git_command(vault.root(), &["rm", "-rf", "--ignore-unmatch",
|
||||
&format!("items/{}.enc", id.as_str()),
|
||||
&format!("attachments/{}", id.as_str()),
|
||||
]).status()?;
|
||||
// Note: caller adds+commits manifest.enc after processing all purges.
|
||||
eprintln!("Purged: {title}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_purge(query: String) -> Result<()> {
|
||||
let vault = crate::session::UnlockedVault::unlock_interactive()?;
|
||||
let mut manifest = vault.load_manifest()?;
|
||||
let entry = super::resolve_query(&manifest, &query)?;
|
||||
let id = entry.id.clone();
|
||||
let title = entry.title.clone();
|
||||
let _ = entry;
|
||||
|
||||
purge_item(&vault, &mut manifest, &id, &title)?;
|
||||
vault.save_manifest(&manifest)?;
|
||||
crate::refresh_groups_cache(vault.root(), &manifest);
|
||||
|
||||
let status = crate::helpers::git_command(vault.root(), &["add", "manifest.enc"]).status()?;
|
||||
if !status.success() { anyhow::bail!("git add manifest.enc failed"); }
|
||||
let status = crate::helpers::git_command(vault.root(),
|
||||
&["commit", "-m", &format!("purge: {} ({})", title, id.as_str())]).status()?;
|
||||
if !status.success() { anyhow::bail!("git commit failed"); }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_trash(action: TrashAction) -> Result<()> {
|
||||
match action {
|
||||
TrashAction::List => super::list::cmd_list(None, None, None, true),
|
||||
TrashAction::Empty => cmd_trash_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmd_trash_empty() -> Result<()> {
|
||||
use relicario_core::time::now_unix;
|
||||
|
||||
let vault = crate::session::UnlockedVault::unlock_interactive()?;
|
||||
let mut manifest = vault.load_manifest()?;
|
||||
let settings = vault.load_settings()?;
|
||||
let now = now_unix();
|
||||
|
||||
let purgeable: Vec<_> = manifest.items.values()
|
||||
.filter(|e| match e.trashed_at {
|
||||
Some(t) => settings.trash_retention.should_purge(t, now),
|
||||
None => false,
|
||||
})
|
||||
.map(|e| (e.id.clone(), e.title.clone()))
|
||||
.collect();
|
||||
|
||||
if purgeable.is_empty() {
|
||||
eprintln!("nothing past retention window");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut purged_titles = Vec::new();
|
||||
for (id, title) in purgeable {
|
||||
purge_item(&vault, &mut manifest, &id, &title)?;
|
||||
purged_titles.push(title);
|
||||
}
|
||||
|
||||
vault.save_manifest(&manifest)?;
|
||||
let status = crate::helpers::git_command(vault.root(), &["add", "manifest.enc"]).status()?;
|
||||
if !status.success() { anyhow::bail!("git add manifest.enc failed"); }
|
||||
let status = crate::helpers::git_command(vault.root(),
|
||||
&["commit", "-m", &format!("trash empty: purged {} item(s)", purged_titles.len())]).status()?;
|
||||
if !status.success() { anyhow::bail!("git commit failed"); }
|
||||
|
||||
eprintln!("Emptied trash: {} item(s)", purged_titles.len());
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user