repo_cli/
cache.rs

1use crate::{config::Config, util, Location, Repository, Tag};
2use anyhow::{anyhow, Context, Result};
3use std::{
4    collections::HashMap,
5    io::Write,
6    path::{Path, PathBuf},
7};
8
9#[derive(Debug)]
10pub struct Cache {
11    data: CacheData,
12}
13
14#[derive(Debug)]
15pub struct CacheData {
16    repositories: HashMap<String, Repository>,
17    tags: HashMap<String, Tag>,
18}
19
20impl Cache {
21    pub fn new() -> Result<Self> {
22        trace!("Loading cache data");
23        Ok(Self {
24            data: CacheData::new()?,
25        })
26    }
27
28    pub fn add_repository(&mut self, repository: Repository) {
29        self.data
30            .repositories
31            .insert(repository.name.clone(), repository);
32    }
33
34    pub fn add_tag(&mut self, tag: Tag) {
35        self.data.tags.insert(tag.name.clone(), tag);
36    }
37
38    pub fn get_repository(&self, name: &str) -> Option<&Repository> {
39        self.data.repositories.get(name)
40    }
41
42    pub fn get_repository_mut(&mut self, name: &str) -> Option<&mut Repository> {
43        self.data.repositories.get_mut(name)
44    }
45
46    pub fn take_repository(&mut self, name: &str) -> Option<Repository> {
47        self.data.repositories.remove(name)
48    }
49
50    pub fn get_tag(&self, name: &str) -> Option<&Tag> {
51        self.data.tags.get(name)
52    }
53
54    pub fn get_tag_mut(&mut self, name: &str) -> Option<&mut Tag> {
55        self.data.tags.get_mut(name)
56    }
57
58    pub fn take_tag(&mut self, name: &str) -> Option<Tag> {
59        self.data.tags.remove(name)
60    }
61
62    /// Check if cache contains a repository with the name as a key
63    pub fn has_repository(&self, name: &str) -> bool {
64        self.data.repositories.contains_key(name)
65    }
66
67    pub fn has_tag(&self, name: &str) -> bool {
68        self.data.tags.contains_key(name)
69    }
70
71    pub fn remove_repository(&mut self, name: &str) -> Result<()> {
72        match self.get_repository(name) {
73            Some(repo) => {
74                std::fs::remove_file(&repo.config).context(format!(
75                    "failed to remove repository config file: {}",
76                    &repo.config.display()
77                ))?;
78                self.data.repositories.remove(name);
79                Ok(())
80            }
81            None => Err(anyhow!("Repository: '{}' is not tracked by repo", name)),
82        }
83    }
84
85    pub fn remove_tag(&mut self, name: &str) -> Result<()> {
86        match self.get_tag(name) {
87            Some(tag) => std::fs::remove_file(&tag.config)
88                .context(format!(
89                    "failed to remove tag config file: {:#?}",
90                    &tag.config
91                ))
92                .map_err(Into::into),
93            None => Err(anyhow!("Tag: '{}' is not in repo", name)),
94        }
95    }
96
97    pub fn repositories(&self) -> Vec<&Repository> {
98        self.data.repositories.values().collect()
99    }
100
101    pub fn tags(&self) -> Vec<&Tag> {
102        self.data.tags.values().collect()
103    }
104}
105
106impl CacheData {
107    pub fn new() -> Result<Self> {
108        let paths = vec![
109            (Config::global_path(), Location::Global),
110            (Config::local_path(), Location::Local),
111        ];
112
113        let mut repositories = HashMap::new();
114        let mut tags = HashMap::new();
115
116        for (path, location) in paths {
117            let repo_path = PathBuf::from(&path).join("repository");
118            debug!("Checking if repository folder exists: {:#?}", repo_path);
119
120            if repo_path.is_dir() {
121                debug!("Repository folder exists");
122                let pattern = format!("{}/*.toml", repo_path.display());
123
124                for entry in glob::glob(&pattern).expect("failed repository glob") {
125                    let file = match entry {
126                        Ok(file) => file,
127                        Err(e) => {
128                            return Err(e).context("file is unreadable");
129                        }
130                    };
131
132                    debug!("Loading Repository: {:#?}", file);
133                    let content = util::read_content(&file)?;
134                    let mut repository: Repository = toml::from_str(&content).context(format!(
135                        "could not serialize content into Repository:\n\n{}",
136                        content
137                    ))?;
138
139                    repository.config = file;
140                    repository.location = location;
141
142                    debug!("Inserting into cache: {}", repository.name);
143                    repositories.insert(repository.name.clone(), repository);
144                }
145            } else {
146                debug!("Repository folder does not exists");
147            };
148
149            let tag_path = PathBuf::from(&path).join("tag");
150            debug!("Checking if tag folder exists: {:#?}", tag_path);
151
152            if tag_path.is_dir() {
153                debug!("Tag folder exists");
154                let pattern = format!("{}/*.toml", tag_path.display());
155
156                for entry in glob::glob(&pattern).expect("failed tag glob") {
157                    let file = match entry {
158                        Ok(file) => file,
159                        Err(e) => {
160                            return Err(e).context("file is unreadable");
161                        }
162                    };
163
164                    debug!("Loading Tag: {:#?}", file);
165                    let content = util::read_content(&file)?;
166                    let mut tag: Tag = toml::from_str(&content).context(format!(
167                        "could not serialize content into Tag:\n\n{}",
168                        content
169                    ))?;
170
171                    tag.config = file;
172                    tag.location = location;
173
174                    debug!("Inserting into cache: {}", tag.name);
175                    tags.insert(tag.name.clone(), tag);
176                }
177            } else {
178                debug!("Tag folder does not exists");
179            };
180        }
181        Ok(Self { repositories, tags })
182    }
183}