use std::path::{Path, PathBuf}; use crate::DOT_GIT_DIR; pub(crate) fn shorten_path_with_cwd(cursor: PathBuf, cwd: &Path) -> PathBuf { fn comp_len(c: std::path::Component<'_>) -> usize { use std::path::Component::*; match c { Prefix(p) => p.as_os_str().len(), CurDir => 1, ParentDir => 2, Normal(p) => p.len(), RootDir => 1, } } debug_assert_eq!(cursor.file_name().and_then(|f| f.to_str()), Some(DOT_GIT_DIR)); let parent = cursor.parent().expect(".git appended"); cwd.strip_prefix(parent) .ok() .and_then(|path_relative_to_cwd| { let relative_path_components = path_relative_to_cwd.components().count(); let current_component_len = cursor.components().map(comp_len).sum::(); (relative_path_components * "..".len() < current_component_len).then(|| { std::iter::repeat("..") .take(relative_path_components) .chain(Some(DOT_GIT_DIR)) .collect() }) }) .unwrap_or(cursor) } /// Find the number of components parenting the `search_dir` before the first directory in `ceiling_dirs`. /// `search_dir` needs to be absolutized, and we absolutize every ceiling as well. pub(crate) fn find_ceiling_height(search_dir: &Path, ceiling_dirs: &[PathBuf], cwd: &Path) -> Option { if ceiling_dirs.is_empty() { return None; } let search_realpath; let search_dir = if search_dir.is_absolute() { search_dir } else { search_realpath = git_path::realpath_opts(search_dir, cwd, git_path::realpath::MAX_SYMLINKS).ok()?; search_realpath.as_path() }; ceiling_dirs .iter() .filter_map(|ceiling_dir| { let mut ceiling_dir = git_path::absolutize(ceiling_dir, cwd)?; if !ceiling_dir.is_absolute() { ceiling_dir = git_path::absolutize(cwd.join(ceiling_dir.as_ref()), cwd)?; } search_dir .strip_prefix(ceiling_dir.as_ref()) .ok() .map(|path_relative_to_ceiling| path_relative_to_ceiling.components().count()) }) .min() } /// Returns the device ID of the directory. #[cfg(target_os = "linux")] pub(crate) fn device_id(m: &std::fs::Metadata) -> u64 { use std::os::linux::fs::MetadataExt; m.st_dev() } /// Returns the device ID of the directory. #[cfg(all(unix, not(target_os = "linux")))] pub(crate) fn device_id(m: &std::fs::Metadata) -> u64 { use std::os::unix::fs::MetadataExt; m.dev() }