joat_repo/
trash.rs

1// Copyright (c) 2023 Richard Cook
2//
3// Permission is hereby granted, free of charge, to any person obtaining
4// a copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to
8// permit persons to whom the Software is furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be
12// included in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21//
22use 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}