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 entire Zoi 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    if dry_run {
66        println!("{} Cleaning cache (Dry-run)...", "::".bold().yellow());
67    } else {
68        println!("{} Cleaning cache...", "::".bold().blue());
69    }
70    crate::pkg::cache::clear(dry_run)?;
71    if !dry_run {
72        println!("{}", "Cache cleaned successfully.".green());
73    }
74    Ok(())
75}
76
77/// Lists files in the local archive cache.
78///
79/// # Errors
80///
81/// Returns an error if the archive cache root cannot be determined or if
82/// reading the directory fails.
83///
84/// # Panics
85///
86/// This function does not explicitly panic.
87pub fn list() -> Result<()> {
88    let archive_cache_root = cache::get_archive_cache_root()?;
89    if !archive_cache_root.exists() {
90        println!("Cache is empty.");
91        return Ok(());
92    }
93
94    println!("{} Archives in local cache:", "::".bold().blue());
95    let mut count = 0;
96    for entry in fs::read_dir(archive_cache_root)? {
97        let entry = entry?;
98        let path = entry.path();
99        if path.is_file() {
100            let filename = path
101                .file_name()
102                .ok_or_else(|| {
103                    let p = path.display();
104                    anyhow!("Path from read_dir has no file name: {p}")
105                })?
106                .to_string_lossy();
107            let size = fs::metadata(&path)?.len();
108            println!(
109                "  - {:<40} ({})",
110                filename.cyan(),
111                crate::pkg::utils::format_bytes(size)
112            );
113            count += 1;
114        }
115    }
116
117    if count == 0 {
118        println!("No archives found in cache.");
119    } else {
120        println!(
121            "
122Total: {count} archives"
123        );
124    }
125
126    Ok(())
127}
128
129/// Adds a new cache mirror URL.
130///
131/// # Errors
132///
133/// Returns an error if the mirror cannot be added to the configuration.
134///
135/// # Panics
136///
137/// This function does not explicitly panic.
138pub fn add_mirror(url: &str) -> Result<()> {
139    crate::pkg::config::add_cache_mirror(url)?;
140    println!("Added cache mirror '{}'.", url.cyan());
141    Ok(())
142}
143
144/// Removes a cache mirror URL.
145///
146/// # Errors
147///
148/// Returns an error if the mirror cannot be removed from the configuration.
149///
150/// # Panics
151///
152/// This function does not explicitly panic.
153pub fn remove_mirror(url: &str) -> Result<()> {
154    crate::pkg::config::remove_cache_mirror(url)?;
155    println!("Removed cache mirror '{}'.", url.cyan());
156    Ok(())
157}
158
159/// Lists all configured cache mirror URLs.
160///
161/// # Errors
162///
163/// Returns an error if the configuration cannot be read.
164///
165/// # Panics
166///
167/// This function does not explicitly panic.
168pub fn list_mirrors() -> Result<()> {
169    let config = crate::pkg::config::read_config()?;
170    if config.cache_mirrors.is_empty() {
171        println!("No cache mirrors configured.");
172        return Ok(());
173    }
174
175    println!("{} Configured cache mirrors:", "::".bold().blue());
176    for mirror in &config.cache_mirrors {
177        println!("  - {}", mirror.cyan());
178    }
179    Ok(())
180}