use crate::disk_cache::DiskCache;
use std::path::PathBuf;
#[derive(Clone)]
pub struct DenoDir {
pub root: PathBuf,
pub gen_cache: DiskCache,
}
impl DenoDir {
pub fn new(maybe_custom_root: Option<PathBuf>) -> std::io::Result<Self> {
let root: PathBuf = if let Some(root) = maybe_custom_root {
if root.is_absolute() {
root
} else {
std::env::current_dir()?.join(root)
}
} else if let Some(cache_dir) = dirs::cache_dir() {
cache_dir.join("deno")
} else if let Some(home_dir) = dirs::home_dir() {
home_dir.join(".deno")
} else {
panic!("Could not set the Deno root directory")
};
assert!(root.is_absolute());
let gen_path = root.join("gen");
let deno_dir = Self {
root,
gen_cache: DiskCache::new(&gen_path),
};
deno_dir.gen_cache.ensure_dir_exists(&gen_path)?;
Ok(deno_dir)
}
}
#[cfg(not(windows))]
mod dirs {
use std::path::PathBuf;
pub fn cache_dir() -> Option<PathBuf> {
if cfg!(target_os = "macos") {
home_dir().map(|h| h.join("Library/Caches"))
} else {
std::env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.or_else(|| home_dir().map(|h| h.join(".cache")))
}
}
pub fn home_dir() -> Option<PathBuf> {
std::env::var_os("HOME")
.and_then(|h| if h.is_empty() { None } else { Some(h) })
.or_else(|| unsafe { fallback() })
.map(PathBuf::from)
}
unsafe fn fallback() -> Option<std::ffi::OsString> {
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
n if n < 0 => 512 as usize,
n => n as usize,
};
let mut buf = Vec::with_capacity(amt);
let mut passwd: libc::passwd = std::mem::zeroed();
let mut result = std::ptr::null_mut();
match libc::getpwuid_r(
libc::getuid(),
&mut passwd,
buf.as_mut_ptr(),
buf.capacity(),
&mut result,
) {
0 if !result.is_null() => {
let ptr = passwd.pw_dir as *const _;
let bytes = std::ffi::CStr::from_ptr(ptr).to_bytes().to_vec();
Some(std::os::unix::ffi::OsStringExt::from_vec(bytes))
}
_ => None,
}
}
}
#[cfg(windows)]
mod dirs {
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use winapi::shared::winerror;
use winapi::um::{combaseapi, knownfolders, shlobj, shtypes, winbase, winnt};
fn known_folder(folder_id: shtypes::REFKNOWNFOLDERID) -> Option<PathBuf> {
unsafe {
let mut path_ptr: winnt::PWSTR = std::ptr::null_mut();
let result = shlobj::SHGetKnownFolderPath(
folder_id,
0,
std::ptr::null_mut(),
&mut path_ptr,
);
if result == winerror::S_OK {
let len = winbase::lstrlenW(path_ptr) as usize;
let path = std::slice::from_raw_parts(path_ptr, len);
let ostr: OsString = OsStringExt::from_wide(path);
combaseapi::CoTaskMemFree(path_ptr as *mut winapi::ctypes::c_void);
Some(PathBuf::from(ostr))
} else {
None
}
}
}
pub fn cache_dir() -> Option<PathBuf> {
known_folder(&knownfolders::FOLDERID_LocalAppData)
}
pub fn home_dir() -> Option<PathBuf> {
known_folder(&knownfolders::FOLDERID_Profile)
}
}