use {
super::bid::BId,
crate::{
errors::TreeBuildError,
git::IgnoreChain,
path::{
Directive,
SpecialHandling,
normalize_path,
},
tree::*,
},
id_arena::Arena,
std::{
fs,
io,
path::PathBuf,
result::Result,
},
};
pub struct BLine {
pub parent_id: Option<BId>,
pub path: PathBuf,
pub depth: u16,
pub file_type: fs::FileType,
pub children: Option<Vec<BId>>, pub next_child_idx: usize, pub has_error: bool,
pub has_match: bool,
pub direct_match: bool,
pub score: i32,
pub nb_kept_children: i32, pub git_ignore_chain: IgnoreChain,
pub special_handling: SpecialHandling,
}
impl BLine {
pub fn name(&self) -> &str {
self.path
.file_name()
.and_then(|os_str| os_str.to_str())
.unwrap_or("")
}
pub fn from_root(
blines: &mut Arena<BLine>,
path: PathBuf,
git_ignore_chain: IgnoreChain,
_options: &TreeOptions,
) -> Result<BId, TreeBuildError> {
if let Ok(md) = fs::metadata(&path) {
let file_type = md.file_type();
Ok(blines.alloc(BLine {
parent_id: None,
path,
depth: 0,
children: None,
next_child_idx: 0,
file_type,
has_error: false,
has_match: true,
direct_match: false,
score: 0,
nb_kept_children: 0,
git_ignore_chain,
special_handling: Default::default(),
}))
} else {
Err(TreeBuildError::FileNotFound {
path: format!("{path:?}"),
})
}
}
pub(crate) fn read_dir(&self) -> io::Result<fs::ReadDir> {
if self.file_type.is_symlink() {
if let Ok(target) = fs::read_link(&self.path) {
let mut target_path = PathBuf::from(&target);
if target_path.is_relative() {
target_path = self.path.parent().unwrap().join(target_path);
target_path = normalize_path(target_path);
}
return fs::read_dir(&target_path);
}
}
fs::read_dir(&self.path)
}
pub fn can_enter(&self) -> bool {
if self.file_type.is_dir() && self.special_handling.list != Directive::Never {
return true;
}
if self.special_handling.list == Directive::Always {
if self.file_type.is_symlink() {
if let Ok(target) = fs::read_link(&self.path) {
let mut target_path = PathBuf::from(&target);
if target_path.is_relative() {
target_path = self.path.parent().unwrap().join(target_path);
}
if let Ok(target_metadata) = fs::symlink_metadata(&target_path) {
if target_metadata.file_type().is_dir() {
if self.path.starts_with(target_path) {
debug!("not entering link because it's a parent"); } else {
debug!("entering {:?} because of special path rule", &self.path);
return true;
}
}
}
}
}
}
false
}
}