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 #[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
33pub 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
54pub 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
64pub 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 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}