use crate::error::{CjvError, Result};
use std::path::{Path, PathBuf};
pub fn current_platform() -> Result<String> {
let os = std::env::consts::OS;
let arch = std::env::consts::ARCH;
let goos = match os {
"linux" => "linux",
"macos" | "darwin" => "darwin",
"windows" => "windows",
_ => return Err(CjvError::UnsupportedPlatform(os.to_string())),
};
let goarch = match arch {
"x86_64" => "amd64",
"aarch64" | "arm64" => "arm64",
_ => return Err(CjvError::UnsupportedPlatform(arch.to_string())),
};
Ok(format!("{}-{}", goos, goarch))
}
pub fn cjv_home() -> PathBuf {
if let Ok(val) = std::env::var("CJV_HOME") {
return PathBuf::from(val);
}
let settings_path = settings_file();
if settings_path.exists() {
if let Ok(content) = std::fs::read_to_string(&settings_path) {
if let Ok(settings) = content.parse::<toml::Value>() {
if let Some(home) = settings.get("home").and_then(|v| v.as_str()) {
return PathBuf::from(home);
}
}
}
}
dirs::home_dir()
.map(|h| h.join(".cjv"))
.unwrap_or_else(|| PathBuf::from(".cjv"))
}
pub fn settings_file() -> PathBuf {
if let Ok(val) = std::env::var("CJV_HOME") {
return PathBuf::from(val).join("settings.toml");
}
dirs::home_dir()
.map(|h| h.join(".cjv").join("settings.toml"))
.unwrap_or_else(|| PathBuf::from(".cjv/settings.toml"))
}
pub fn ensure_dir(path: &Path) -> Result<()> {
std::fs::create_dir_all(path).map_err(|e| {
CjvError::Other(format!(
"Failed to create directory {}: {}",
path.display(),
e
))
})
}
pub fn create_symlink(target: &Path, link: &Path) -> Result<()> {
#[cfg(unix)]
{
std::os::unix::fs::symlink(target, link)?;
}
#[cfg(windows)]
{
if target.is_dir() {
std::os::windows::fs::symlink_dir(target, link)?;
} else {
std::os::windows::fs::symlink_file(target, link)?;
}
}
Ok(())
}
pub fn is_valid_channel(name: &str) -> bool {
matches!(name, "lts" | "sts" | "nightly")
}
pub fn is_reserved_name(name: &str) -> bool {
is_valid_channel(name)
|| name.starts_with("lts-")
|| name.starts_with("sts-")
|| name.starts_with("nightly-")
}
pub fn is_unsafe_cjv_home(path: &Path) -> bool {
if path == Path::new("/") || path.as_os_str().is_empty() {
return true;
}
#[cfg(windows)]
{
if path.components().count() <= 1 {
return true;
}
}
dirs::home_dir()
.map(|h| h == path)
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detects_filesystem_root_as_unsafe_home() {
assert!(is_unsafe_cjv_home(Path::new("/")));
assert!(is_unsafe_cjv_home(Path::new("")));
}
#[test]
fn detects_user_home_as_unsafe_home() {
if let Some(home) = dirs::home_dir() {
assert!(is_unsafe_cjv_home(&home));
}
}
#[test]
fn normal_cjv_home_is_safe() {
let temp = tempfile::tempdir().unwrap();
let home = temp.path().join(".cjv");
assert!(!is_unsafe_cjv_home(&home));
}
}