2020-01-02 15:13:47 -05:00
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
2020-09-05 20:34:02 -04:00
2019-07-17 18:15:30 -04:00
use crate ::disk_cache ::DiskCache ;
2018-07-26 17:54:22 -04:00
use std ::path ::PathBuf ;
2019-06-24 12:04:06 -04:00
2019-07-17 18:15:30 -04:00
/// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them
/// in single directory that can be controlled with `$DENO_DIR` env variable.
2019-04-01 21:46:40 -04:00
#[ derive(Clone) ]
2018-07-26 17:54:22 -04:00
pub struct DenoDir {
2020-06-20 23:49:27 -04:00
/// Example: /Users/rld/.deno/
2018-07-26 17:54:22 -04:00
pub root : PathBuf ,
2019-07-31 07:58:41 -04:00
/// Used by TsCompiler to cache compiler output.
pub gen_cache : DiskCache ,
2018-07-26 17:54:22 -04:00
}
impl DenoDir {
2020-05-15 10:32:52 -04:00
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 )
}
2020-07-13 12:24:54 -04:00
} else if let Some ( cache_dir ) = dirs ::cache_dir ( ) {
// We use the OS cache dir because all files deno writes are cache files
// Once that changes we need to start using different roots if DENO_DIR
// is not set, and keep a single one if it is.
cache_dir . join ( " deno " )
} else if let Some ( home_dir ) = dirs ::home_dir ( ) {
// fallback path
home_dir . join ( " .deno " )
2020-05-15 10:32:52 -04:00
} else {
2020-07-13 12:24:54 -04:00
panic! ( " Could not set the Deno root directory " )
2020-05-15 10:32:52 -04:00
} ;
assert! ( root . is_absolute ( ) ) ;
2019-07-31 07:58:41 -04:00
let gen_path = root . join ( " gen " ) ;
2019-04-29 10:58:31 -04:00
2018-11-05 01:21:21 -05:00
let deno_dir = Self {
2018-08-14 16:50:53 -04:00
root ,
2019-07-31 07:58:41 -04:00
gen_cache : DiskCache ::new ( & gen_path ) ,
2018-08-14 16:50:53 -04:00
} ;
2020-05-24 13:20:40 -04:00
deno_dir . gen_cache . ensure_dir_exists ( & gen_path ) ? ;
2019-01-17 23:39:06 -05:00
2018-07-26 17:54:22 -04:00
Ok ( deno_dir )
}
2019-07-17 18:15:30 -04:00
}
2020-06-20 23:49:27 -04:00
/// To avoid the poorly managed dirs crate
#[ 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 ) } )
2020-07-13 12:24:54 -04:00
. or_else ( | | unsafe { fallback ( ) } )
2020-06-20 23:49:27 -04:00
. map ( PathBuf ::from )
}
2020-07-13 12:24:54 -04:00
// This piece of code is taken from the deprecated home_dir() function in Rust's standard library: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/os.rs#L579
// The same code is used by the dirs crate
unsafe fn fallback ( ) -> Option < std ::ffi ::OsString > {
let amt = match libc ::sysconf ( libc ::_SC_GETPW_R_SIZE_MAX ) {
2020-11-27 14:47:35 -05:00
n if n < 0 = > 512_ usize ,
2020-07-13 12:24:54 -04:00
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 ,
}
}
2020-06-20 23:49:27 -04:00
}
/// To avoid the poorly managed dirs crate
// Copied from
// https://github.com/dirs-dev/dirs-sys-rs/blob/ec7cee0b3e8685573d847f0a0f60aae3d9e07fa2/src/lib.rs#L140-L164
// MIT license. Copyright (c) 2018-2019 dirs-rs contributors
#[ 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 )
}
}