1use crate::error::RepoError;
23use crate::link::Link;
24use crate::manifest::Manifest;
25use crate::repo::Repo;
26use crate::result::RepoResult;
27use std::collections::HashMap;
28use std::fmt::Debug;
29use std::fs::{remove_dir_all, remove_file};
30
31#[derive(Debug)]
32pub struct Trash {
33 pub unreferenced_manifests: Vec<Manifest>,
34 pub invalid_links: Vec<Link>,
35}
36
37struct ManifestStatus {
38 manifest: Manifest,
39 is_referenced: bool,
40}
41
42struct LinkStatus {
43 link: Link,
44 is_valid: bool,
45}
46
47impl Trash {
48 pub fn compute(repo: &Repo) -> RepoResult<Self> {
49 let mut manifest_map = repo
50 .list_manifests()?
51 .into_iter()
52 .map(|m| {
53 (
54 m.meta_id().clone(),
55 ManifestStatus {
56 manifest: m,
57 is_referenced: false,
58 },
59 )
60 })
61 .collect::<HashMap<_, _>>();
62
63 let mut link_map = repo
64 .list_links()?
65 .into_iter()
66 .map(|l| {
67 (
68 l.link_id().clone(),
69 LinkStatus {
70 link: l,
71 is_valid: true,
72 },
73 )
74 })
75 .collect::<HashMap<_, _>>();
76
77 for l in link_map.values_mut() {
78 if l.link.project_dir().is_dir() {
79 match manifest_map.get_mut(l.link.meta_id()) {
80 Some(m) => m.is_referenced = true,
81 None => l.is_valid = false,
82 }
83 } else {
84 l.is_valid = false;
85 }
86 }
87
88 let invalid_links = link_map
89 .into_values()
90 .filter(|x| !x.is_valid)
91 .map(|x| x.link)
92 .collect::<Vec<_>>();
93 let unreferenced_manifests = manifest_map
94 .into_values()
95 .filter(|x| !x.is_referenced)
96 .map(|x| x.manifest)
97 .collect::<Vec<_>>();
98
99 Ok(Self {
100 unreferenced_manifests,
101 invalid_links,
102 })
103 }
104
105 #[must_use]
106 pub fn is_empty(&self) -> bool {
107 self.invalid_links.len() + self.unreferenced_manifests.len() == 0
108 }
109
110 pub fn empty(&mut self) -> RepoResult<()> {
111 for l in self.invalid_links.drain(..) {
112 remove_file(l.link_path())
113 .map_err(|_e| RepoError::could_not_delete_file(l.link_path()))?;
114 }
115
116 for m in self.unreferenced_manifests.drain(..) {
117 remove_dir_all(m.data_dir())
118 .map_err(|_e| RepoError::could_not_delete_directory(m.data_dir()))?;
119 }
120
121 Ok(())
122 }
123}