about summary refs log tree commit diff
path: root/pkgs/profpatsch/lru.nix
blob: e62bd29e7a6e01d2c2add7fd8f0dde959934edec (plain) (blame)
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
73
{ pkgs, writeRustSimple }:

let

  # Given a directory, finds all files directly in that directory.
  # If the size of all files (ignoring symlinks and directories)
  # is bigger than MAX_SIZE, delete the 25% files with oldest mtime.
  #
  # Only deletes
  lru-dir = writeRustSimple "lru-dir" {} (pkgs.writeText "main.rs" ''
    use std::fs;
    use std::convert::identity;
    use std::path::Path;

    const MAX_SIZE : usize = 200 * 1000*1000; // 200 MB

    fn main() -> std::io::Result<()> {
      let mut args = std::env::args_os();
      let dir = args.nth(1).unwrap();
      // only files, only in dir
      // ignore all files that can’t be read
      let mut files = std::fs::read_dir(&dir)?
        .filter_map(|f| f.ok())
        .filter_map(|f| f.metadata().ok()
                         .map(|m| (f.path(), m)))
        .filter(|f| f.1.is_file())
        .collect::<Vec<(std::path::PathBuf, std::fs::Metadata)>>();
      let size : usize = files.iter().map(|f| f.1.len() as usize).sum();

      if size > MAX_SIZE {
        let all = files.len();
        // keep ~75% of files (no floats required)
        let to_keep : usize = (all >> 1) + (all >> 2);
        let to_delete : usize = all - to_keep;

        println!("{} is {} bytes (MAX = {})", &Path::new(&dir).display(), size, MAX_SIZE);
        println!("to keep: {}, to delete: {}", to_keep, to_delete);

        let really_delete = std::env::var("REALLY_DELETE").ok();

        if let None = really_delete {
          println!("dry-running. If you want to actually delete files, set REALLY_DELETE");
        }

        // sort oldest files to the front
        files.sort_by_cached_key(|f| f.1.modified().ok());

        for f in files.iter().take(to_delete) {
          match really_delete {
            None => {
              println!("Would delete: {}", f.0.display());
            },
            Some(_) => {
              println!("Deleting: {}", f.0.display());
              if let Err(e) = fs::remove_file(&f.0) {
                println!("Warning: could not remove {}: {:?}", f.0.display(), e);
              }
            }
          }
        }

      }

      Ok(())
    }
  '');


in {
  inherit
    lru-dir
    ;
}