A clean-up with the downloads folder gone forgets no file (#293)
missing_files took every path that did not exist() as deleted by hand. With /downloads out of reach (the array stopped, shfs dropped) that is every file, and each would have been marked reaped at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,9 +45,17 @@ pub fn aged(candidates: &[Candidate], cutoff: i64) -> Vec<Candidate> {
|
||||
pub async fn run(cfg: &Config, db: &Db, dry_run: bool) -> Result<Report> {
|
||||
let mut report = Report::default();
|
||||
|
||||
// Someone may have deleted a file by hand; the row must stop claiming it exists.
|
||||
// Someone may have deleted a file by hand; the row must stop claiming it exists. Not while
|
||||
// the folder itself is gone (the array stopped, shfs dropped): every file would look deleted
|
||||
// and the whole library be forgotten at once (#293).
|
||||
// Each step is a span of the reap's trace, so a slow one says which part was slow.
|
||||
for (id, path) in db.missing_files().instrument(step("missing_files")).await? {
|
||||
let missing = if cfg.general.download_dir.is_dir() {
|
||||
db.missing_files().instrument(step("missing_files")).await?
|
||||
} else {
|
||||
tracing::warn!(dir = %cfg.general.download_dir.display(), "the downloads folder is not there; left every file as it was");
|
||||
vec![]
|
||||
};
|
||||
for (id, path) in missing {
|
||||
if !dry_run {
|
||||
db.mark_reaped(id).await?;
|
||||
}
|
||||
@@ -204,6 +212,23 @@ mod tests {
|
||||
assert_eq!(db.prune_entries(500).await.unwrap(), 1, "the old item goes, a leaver's pin or not");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_downloads_folder_that_is_gone_forgets_no_file() {
|
||||
let db = Db::memory().await.unwrap();
|
||||
db.exec_for_test(
|
||||
"INSERT INTO enclosures (id, feed_id, guid, url, path, state) VALUES
|
||||
(1, 'f', 'a', 'u1', '/nowhere/ipx-test/a.mp3', 'done');",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut cfg = Config::default();
|
||||
cfg.general.download_dir = "/nowhere/ipx-test".into();
|
||||
assert_eq!(run(&cfg, &db, false).await.unwrap().reconciled, 0, "the folder is gone, not the file");
|
||||
|
||||
cfg.general.download_dir = std::env::temp_dir();
|
||||
assert_eq!(run(&cfg, &db, false).await.unwrap().reconciled, 1, "the folder is there and the file is not");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn prune_keeps_entries_that_still_have_a_file() {
|
||||
let db = Db::memory().await.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user