1 use crate::error::Result;
2 use crate::gen::fs;
3 use std::ffi::OsStr;
4 use std::path::{Component, Path, PathBuf};
5 
manifest_dir() -> Result<PathBuf>6 pub(crate) fn manifest_dir() -> Result<PathBuf> {
7     crate::env_os("CARGO_MANIFEST_DIR").map(PathBuf::from)
8 }
9 
out_dir() -> Result<PathBuf>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.
local_relative_path(path: &Path) -> PathBuf18 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_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf31     fn with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf;
32 }
33 
34 impl PathExt for Path {
with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf35     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)]
symlink_or_copy( path_for_symlink: impl AsRef<Path>, _path_for_copy: impl AsRef<Path>, link: impl AsRef<Path>, ) -> fs::Result<()>43 pub(crate) fn symlink_or_copy(
44     path_for_symlink: impl AsRef<Path>,
45     _path_for_copy: impl AsRef<Path>,
46     link: impl AsRef<Path>,
47 ) -> fs::Result<()> {
48     fs::symlink_file(path_for_symlink, link)
49 }
50 
51 #[cfg(windows)]
symlink_or_copy( path_for_symlink: impl AsRef<Path>, path_for_copy: impl AsRef<Path>, link: impl AsRef<Path>, ) -> fs::Result<()>52 pub(crate) fn symlink_or_copy(
53     path_for_symlink: impl AsRef<Path>,
54     path_for_copy: impl AsRef<Path>,
55     link: impl AsRef<Path>,
56 ) -> fs::Result<()> {
57     // Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
58     // require Developer Mode. If it fails, fall back to copying the file.
59     let path_for_symlink = path_for_symlink.as_ref();
60     let link = link.as_ref();
61     if fs::symlink_file(path_for_symlink, link).is_err() {
62         let path_for_copy = path_for_copy.as_ref();
63         fs::copy(path_for_copy, link)?;
64     }
65     Ok(())
66 }
67 
68 #[cfg(not(any(unix, windows)))]
symlink_or_copy( _path_for_symlink: impl AsRef<Path>, path_for_copy: impl AsRef<Path>, copy: impl AsRef<Path>, ) -> fs::Result<()>69 pub(crate) fn symlink_or_copy(
70     _path_for_symlink: impl AsRef<Path>,
71     path_for_copy: impl AsRef<Path>,
72     copy: impl AsRef<Path>,
73 ) -> fs::Result<()> {
74     fs::copy(path_for_copy, copy)?;
75     Ok(())
76 }
77