~iptq/garbage

ref: 45fc4f1ee1bf4703e50eaed3e5f61ee06a7f6f81 garbage/src/ops/restore.rs -rw-r--r-- 2.0 KiB
45fc4f1e — Michael Zhang add sourcehut build badge and remove deps.rs one 1 year, 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use std::fs;
use std::io;
use std::path::PathBuf;

use anyhow::Result;

use crate::TrashDir;

/// Options to pass to restore
#[derive(StructOpt)]
pub struct RestoreOptions {
    /// The path to the trash directory to restore from.
    /// By default, this is your home directory's trash ($XDG_DATA_HOME/Trash)
    #[structopt(long = "trash-dir", parse(from_os_str))]
    trash_dir: Option<PathBuf>,
}

/// Restore files from a trash directory
pub fn restore(options: RestoreOptions) -> Result<()> {
    let trash_dir = TrashDir::from_opt(options.trash_dir);

    if trash_dir.check_info_dir()?.is_none() {
        bail!("There's no trash directory here.");
    }

    // get list of files sorted by deletion date
    // TODO: possible to get this to be streaming?
    let files = {
        let mut files = trash_dir
            .iter()
            .unwrap()
            .filter_map(|entry| match entry {
                Ok(info) => Some(info),
                Err(err) => {
                    eprintln!("failed to get file info: {:?}", err);
                    None
                }
            })
            .collect::<Vec<_>>();
        files.sort_unstable_by_key(|info| info.deletion_date);
        files
    };

    if files.len() == 0 {
        bail!("No files in this trash directory.");
    }

    for (i, info) in files.iter().enumerate() {
        println!(
            "[{}]\t{}\t{}",
            i,
            info.deletion_date,
            info.path.to_str().unwrap()
        );
    }

    let stdin = io::stdin();
    let mut s = String::new();
    eprintln!("which file to restore? [0..{}]", files.len() - 1);
    stdin.read_line(&mut s).unwrap();

    match s.trim_end().parse::<usize>() {
        Ok(i) if i < files.len() => {
            let info = &files[i]; // should never fail since we just checked
            eprintln!("moving {:?} to {:?}", &info.deleted_path, &info.path);
            fs::remove_file(&info.info_path)?;
            fs::rename(&info.deleted_path, &info.path)?;
        }
        _ => eprintln!("Invalid number."),
    }
    Ok(())
}