1 use crate::error::Result; 2 use crate::gen::fs; 3 use std::ffi::OsStr; 4 use std::path::{Component, Path, PathBuf}; 5 6 pub(crate) fn manifest_dir() -> Result<PathBuf> { 7 crate::env_os("CARGO_MANIFEST_DIR").map(PathBuf::from) 8 } 9 10 pub(crate) fn out_dir() -> Result<PathBuf> { 11 crate::env_os("OUT_DIR").map(PathBuf::from) 12 } 13 14 // Given a path provided by the user, determines where generated files related 15 // to that path should go in our out dir. In particular we don't want to 16 // accidentally write generated code upward of our out dir, even if the user 17 // passed a path containing lots of `..` or an absolute path. 18 pub(crate) fn local_relative_path(path: &Path) -> PathBuf { 19 let mut rel_path = PathBuf::new(); 20 for component in path.components() { 21 match component { 22 Component::Prefix(_) | Component::RootDir | Component::CurDir => {} 23 Component::ParentDir => drop(rel_path.pop()), // noop if empty 24 Component::Normal(name) => rel_path.push(name), 25 } 26 } 27 rel_path 28 } 29 30 pub(crate) trait PathExt { with_appended_extensionnull31 fn with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf; 32 } 33 34 impl PathExt for Path { with_appended_extensionnull35 fn with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf { 36 let mut file_name = self.file_name().unwrap().to_owned(); 37 file_name.push(suffix); 38 self.with_file_name(file_name) 39 } 40 } 41 42 #[cfg(unix)] 43 pub(crate) use self::fs::symlink_file as symlink_or_copy; 44 45 #[cfg(windows)] 46 pub(crate) fn symlink_or_copy( 47 original: impl AsRef<Path>, 48 link: impl AsRef<Path>, 49 ) -> fs::Result<()> { 50 // Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they 51 // require Developer Mode. If it fails, fall back to copying the file. 52 let original = original.as_ref(); 53 let link = link.as_ref(); 54 if fs::symlink_file(original, link).is_err() { 55 fs::copy(original, link)?; 56 } 57 Ok(()) 58 } 59 60 #[cfg(not(any(unix, windows)))] 61 pub(crate) fn symlink_or_copy( 62 original: impl AsRef<Path>, 63 copy: impl AsRef<Path>, 64 ) -> fs::Result<()> { 65 fs::copy(original, copy)?; 66 Ok(()) 67 } 68