nix_query/
cache.rs

1use std::fs;
2use std::fs::File;
3use std::io;
4use std::io::{Read, Write};
5use std::path::PathBuf;
6
7use dirs;
8use lazy_static::lazy_static;
9
10use crate::nix;
11use crate::proc::CommandError;
12
13/// This uniquely identifies this program (nix-query) so that our cache files
14/// don't conflict with anything else.
15const UUID: &str = "bfe01d7a-c700-4529-acf1-88065df2cd25";
16
17lazy_static! {
18    static ref CACHE_PATH: Option<PathBuf> = {
19        Some(
20            [
21                dirs::cache_dir()?,
22                format!("nix-query-{}.cache", UUID).into(),
23            ]
24            .iter()
25            .collect(),
26        )
27    };
28}
29
30pub const NIX_ATTRS_COUNT_ESTIMATE: usize = 100_000;
31/// Bytes.
32pub const NIX_ATTRS_FILE_SIZE_ESTIMATE: usize = 5_000_000;
33
34pub fn cache_exists() -> bool {
35    CACHE_PATH.as_ref().map(|p| p.is_file()).unwrap_or(false)
36}
37
38#[derive(Debug)]
39pub enum CacheIoError {
40    NoCachePath,
41    Command(CommandError),
42    Io(Box<io::Error>),
43}
44
45impl From<io::Error> for CacheIoError {
46    fn from(e: io::Error) -> CacheIoError {
47        CacheIoError::Io(Box::new(e))
48    }
49}
50
51pub fn clear_cache() -> Result<(), CacheIoError> {
52    match fs::remove_file(CACHE_PATH.as_ref().ok_or(CacheIoError::NoCachePath)?) {
53        Ok(()) => Ok(()),
54        Err(io_err) =>
55        // If we try to remove the cache file but it doesn't exist yet, that's OK.
56        {
57            if let io::ErrorKind::NotFound = io_err.kind() {
58                Ok(())
59            } else {
60                Err(io_err.into())
61            }
62        }
63    }
64}
65
66pub fn write_cache(nix_attrs: &[u8]) -> Result<(), CacheIoError> {
67    File::create(CACHE_PATH.as_ref().ok_or(CacheIoError::NoCachePath)?)?
68        .write_all(nix_attrs)
69        .map_err(Into::into)
70}
71
72pub fn read_cache() -> Result<String, CacheIoError> {
73    let mut cache_file = File::open(CACHE_PATH.as_ref().ok_or(CacheIoError::NoCachePath)?)?;
74    let mut ret = String::with_capacity(NIX_ATTRS_FILE_SIZE_ESTIMATE);
75    cache_file.read_to_string(&mut ret)?;
76    Ok(ret)
77}
78
79pub fn ensure_cache() -> Result<String, CacheIoError> {
80    if !cache_exists() {
81        let attrs = nix::nix_query_all().map_err(CacheIoError::Command)?;
82        write_cache(attrs.as_bytes())?;
83        Ok(attrs)
84    } else {
85        read_cache()
86    }
87}