1use guicons_core::IconEntrySource;
2use std::path::Path;
3
4#[derive(Debug)]
5pub struct FetchSummary {
6 pub fetched: Vec<String>,
7 pub skipped: Vec<String>,
8 pub failed: Vec<(String, String)>,
9}
10
11impl FetchSummary {
12 pub fn is_success(&self) -> bool {
13 self.failed.is_empty()
14 }
15}
16
17pub fn fetch(manifest_path: &Path, cache_search_start: &Path, force: bool) -> Result<FetchSummary, Vec<String>> {
24 let (manifest, errors) = guicons_core::load_icon_manifest(manifest_path);
25 if !errors.is_empty() {
26 return Err(errors.iter().map(|e| e.to_string()).collect());
27 }
28
29 let mut summary = FetchSummary {
30 fetched: Vec::new(),
31 skipped: Vec::new(),
32 failed: Vec::new(),
33 };
34
35 for entry in manifest.entries() {
36 let (cache_path, url, label) = match entry.source() {
37 IconEntrySource::Iconify(id) => (
38 guicons_net::iconify_cache_path(cache_search_start, id),
39 guicons_net::iconify_url(id),
40 id.clone(),
41 ),
42 IconEntrySource::Url(url) => {
43 (guicons_net::url_cache_path(cache_search_start, url), url.clone(), url.clone())
44 }
45 IconEntrySource::File(_) | IconEntrySource::Glyph(_) => continue,
46 };
47
48 if cache_path.exists() && !force {
49 summary.skipped.push(label);
50 continue;
51 }
52
53 match guicons_net::download(&url, &cache_path) {
54 Ok(()) => summary.fetched.push(label),
55 Err(e) => summary.failed.push((label, e.to_string())),
56 }
57 }
58
59 Ok(summary)
60}