Skip to main content

zoi_cli/cmd/
cache.rs

1//! Implementation of the `cache` command for managing the local package cache.
2
3use std::fs;
4use std::path::PathBuf;
5
6use anyhow::{Result, anyhow};
7use colored::Colorize;
8
9use crate::pkg::cache;
10
11/// Adds files to the local archive cache.
12///
13/// # Errors
14///
15/// Returns an error if the archive cache root cannot be determined or if
16/// copying files fails.
17///
18/// # Panics
19///
20/// This function does not explicitly panic.
21pub fn add(files: &[PathBuf]) -> Result<()> {
22    let archive_cache_root = cache::get_archive_cache_root()?;
23    fs::create_dir_all(&archive_cache_root)?;
24
25    for file in files {
26        if !file.exists() {
27            eprintln!(
28                "{}: File not found: {}",
29                "Error".red().bold(),
30                file.display()
31            );
32            continue;
33        }
34        if !file.is_file() {
35            eprintln!(
36                "{}: Not a file: {}",
37                "Error".red().bold(),
38                file.display()
39            );
40            continue;
41        }
42
43        let filename = file
44            .file_name()
45            .ok_or_else(|| anyhow!("Invalid filename"))?;
46        let dest_path = archive_cache_root.join(filename);
47
48        println!("Adding {} to cache...", filename.to_string_lossy().cyan());
49        fs::copy(file, &dest_path)?;
50    }
51
52    Ok(())
53}
54
55/// Clears the local archive cache.
56///
57/// # Errors
58///
59/// Returns an error if the cache clearing operation fails.
60///
61/// # Panics
62///
63/// This function does not explicitly panic.
64pub fn clear(dry_run: bool) -> Result<()> {
65    crate::cmd::clean::run(dry_run)
66}
67
68/// Lists files in the local archive cache.
69///
70/// # Errors
71///
72/// Returns an error if the archive cache root cannot be determined or if
73/// reading the directory fails.
74///
75/// # Panics
76///
77/// This function does not explicitly panic.
78pub fn list() -> Result<()> {
79    let archive_cache_root = cache::get_archive_cache_root()?;
80    if !archive_cache_root.exists() {
81        println!("Cache is empty.");
82        return Ok(());
83    }
84
85    println!("{} Archives in local cache:", "::".bold().blue());
86    let mut count = 0;
87    for entry in fs::read_dir(archive_cache_root)? {
88        let entry = entry?;
89        let path = entry.path();
90        if path.is_file() {
91            let filename = path
92                .file_name()
93                .ok_or_else(|| {
94                    let p = path.display();
95                    anyhow!("Path from read_dir has no file name: {p}")
96                })?
97                .to_string_lossy();
98            let size = fs::metadata(&path)?.len();
99            println!(
100                "  - {:<40} ({})",
101                filename.cyan(),
102                crate::pkg::utils::format_bytes(size)
103            );
104            count += 1;
105        }
106    }
107
108    if count == 0 {
109        println!("No archives found in cache.");
110    } else {
111        println!(
112            "
113Total: {count} archives"
114        );
115    }
116
117    Ok(())
118}
119
120/// Adds a new cache mirror URL.
121///
122/// # Errors
123///
124/// Returns an error if the mirror cannot be added to the configuration.
125///
126/// # Panics
127///
128/// This function does not explicitly panic.
129pub fn add_mirror(url: &str) -> Result<()> {
130    crate::pkg::config::add_cache_mirror(url)?;
131    println!("Added cache mirror '{}'.", url.cyan());
132    Ok(())
133}
134
135/// Removes a cache mirror URL.
136///
137/// # Errors
138///
139/// Returns an error if the mirror cannot be removed from the configuration.
140///
141/// # Panics
142///
143/// This function does not explicitly panic.
144pub fn remove_mirror(url: &str) -> Result<()> {
145    crate::pkg::config::remove_cache_mirror(url)?;
146    println!("Removed cache mirror '{}'.", url.cyan());
147    Ok(())
148}
149
150/// Lists all configured cache mirror URLs.
151///
152/// # Errors
153///
154/// Returns an error if the configuration cannot be read.
155///
156/// # Panics
157///
158/// This function does not explicitly panic.
159pub fn list_mirrors() -> Result<()> {
160    let config = crate::pkg::config::read_config()?;
161    if config.cache_mirrors.is_empty() {
162        println!("No cache mirrors configured.");
163        return Ok(());
164    }
165
166    println!("{} Configured cache mirrors:", "::".bold().blue());
167    for mirror in &config.cache_mirrors {
168        println!("  - {}", mirror.cyan());
169    }
170    Ok(())
171}