Skip to main content

dfx_core/config/
cache.rs

1#[cfg(windows)]
2use crate::config::directories::project_dirs;
3use crate::error::cache::{
4    DeleteCacheError, EnsureCacheVersionsDirError, GetCacheRootError, GetVersionFromCachePathError,
5    IsCacheInstalledError, ListCacheVersionsError,
6};
7#[cfg(not(windows))]
8use crate::foundation::get_user_home;
9use crate::fs::composite::ensure_dir_exists;
10use semver::Version;
11use std::path::{Path, PathBuf};
12
13pub fn get_cache_root() -> Result<PathBuf, GetCacheRootError> {
14    let cache_root = std::env::var_os("DFX_CACHE_ROOT");
15    // dirs-next is not used for *nix to preserve existing paths
16    #[cfg(not(windows))]
17    let p = {
18        let home = get_user_home()?;
19        let root = cache_root.unwrap_or(home);
20        PathBuf::from(root).join(".cache").join("dfinity")
21    };
22    #[cfg(windows)]
23    let p = match cache_root {
24        Some(var) => PathBuf::from(var),
25        None => project_dirs()?.cache_dir().to_owned(),
26    };
27    if p.exists() && !p.is_dir() {
28        return Err(GetCacheRootError::FindCacheDirectoryFailed(p));
29    }
30    Ok(p)
31}
32
33/// Constructs and returns <cache root>/versions/<version> without creating any directories.
34pub fn get_cache_path_for_version(v: &str) -> Result<PathBuf, GetCacheRootError> {
35    let p = get_cache_root()?.join("versions").join(v);
36    Ok(p)
37}
38
39pub fn get_version_from_cache_path(
40    cache_path: &Path,
41) -> Result<Version, GetVersionFromCachePathError> {
42    let version = cache_path
43        .file_name()
44        .ok_or(GetVersionFromCachePathError::NoCachePathFilename(
45            cache_path.to_path_buf(),
46        ))?
47        .to_str()
48        .ok_or(GetVersionFromCachePathError::CachePathFilenameNotUtf8(
49            cache_path.to_path_buf(),
50        ))?;
51    Ok(Version::parse(version)?)
52}
53
54/// Return the binary cache root. It constructs it if not present
55/// already.
56pub fn ensure_cache_versions_dir() -> Result<PathBuf, EnsureCacheVersionsDirError> {
57    let p = get_cache_root()?.join("versions");
58
59    ensure_dir_exists(&p)?;
60
61    Ok(p)
62}
63
64/// Doesn't create the version dir, but does create everything up to it
65pub fn get_bin_cache(v: &str) -> Result<PathBuf, EnsureCacheVersionsDirError> {
66    let root = ensure_cache_versions_dir()?;
67    Ok(root.join(v))
68}
69
70pub fn is_version_installed(v: &str) -> Result<bool, IsCacheInstalledError> {
71    Ok(get_bin_cache(v)?.is_dir())
72}
73
74pub fn delete_version(v: &str) -> Result<bool, DeleteCacheError> {
75    if !is_version_installed(v).unwrap_or(false) {
76        return Ok(false);
77    }
78
79    let root = get_bin_cache(v)?;
80    crate::fs::remove_dir_all(&root)?;
81
82    Ok(true)
83}
84
85pub fn get_binary_path_from_version(
86    version: &str,
87    binary_name: &str,
88) -> Result<PathBuf, EnsureCacheVersionsDirError> {
89    let env_var_name = format!("DFX_{}_PATH", binary_name.replace('-', "_").to_uppercase());
90
91    if let Ok(path) = std::env::var(env_var_name) {
92        return Ok(PathBuf::from(path));
93    }
94
95    Ok(get_bin_cache(version)?.join(binary_name))
96}
97
98pub fn binary_command_from_version(
99    version: &str,
100    name: &str,
101) -> Result<std::process::Command, EnsureCacheVersionsDirError> {
102    let path = get_binary_path_from_version(version, name)?;
103    let cmd = std::process::Command::new(path);
104
105    Ok(cmd)
106}
107
108pub fn list_versions() -> Result<Vec<Version>, ListCacheVersionsError> {
109    let root = ensure_cache_versions_dir()?;
110    let mut result: Vec<Version> = Vec::new();
111
112    for entry in crate::fs::read_dir(&root)? {
113        let entry = entry.map_err(ListCacheVersionsError::ReadCacheEntryFailed)?;
114        if let Some(version) = entry.file_name().to_str() {
115            if version.starts_with('_') {
116                // temp directory for version being installed
117                continue;
118            }
119            result.push(Version::parse(version).map_err(|e| {
120                ListCacheVersionsError::MalformedSemverString(version.to_string(), e)
121            })?);
122        }
123    }
124
125    Ok(result)
126}