Ignore .git, .hg, etc while looking for ignore files

This commit is contained in:
Félix Saparelli 2022-01-16 02:36:22 +13:00
parent 1c388d6b2d
commit ed6df57aa0
No known key found for this signature in database
GPG key ID: B948C4BAE44FC474
2 changed files with 78 additions and 43 deletions

View file

@ -115,34 +115,14 @@ pub async fn from_origin(path: impl AsRef<Path>) -> (Vec<IgnoreFile>, Vec<Error>
)
.await;
trace!("create IgnoreFilterer for visiting directories");
let mut search_filter = IgnoreFilterer::new(&base, &files)
.await
.map_err(|err| errors.push(Error::new(ErrorKind::Other, err)))
.ok();
trace!("visiting child directories for ignore files");
match dunce::canonicalize(base) {
Ok(base) => {
let mut dirs = DirTourist::new(base.clone());
match DirTourist::new(&base, &files).await {
Ok(mut dirs) => {
loop {
match dirs.next().await {
Visit::Done => break,
Visit::Skip => continue,
Visit::Find(dir) => {
if dir == base {
trace!(?dir, "dir is the base, continuing");
continue;
}
if let Some(sf) = &search_filter {
if !sf.check_dir(&dir) {
trace!(?dir, "dir is ignored, adding to skip list");
dirs.skip(dir);
continue;
}
}
if discover_file(
&mut files,
&mut errors,
@ -152,7 +132,7 @@ pub async fn from_origin(path: impl AsRef<Path>) -> (Vec<IgnoreFile>, Vec<Error>
)
.await
{
add_last_file_to_filter(&mut search_filter, &mut files, &mut errors)
dirs.add_last_file_to_filter(&mut files, &mut errors)
.await;
}
@ -165,7 +145,7 @@ pub async fn from_origin(path: impl AsRef<Path>) -> (Vec<IgnoreFile>, Vec<Error>
)
.await
{
add_last_file_to_filter(&mut search_filter, &mut files, &mut errors)
dirs.add_last_file_to_filter(&mut files, &mut errors)
.await;
}
@ -178,7 +158,7 @@ pub async fn from_origin(path: impl AsRef<Path>) -> (Vec<IgnoreFile>, Vec<Error>
)
.await
{
add_last_file_to_filter(&mut search_filter, &mut files, &mut errors)
dirs.add_last_file_to_filter(&mut files, &mut errors)
.await;
}
}
@ -350,6 +330,7 @@ struct DirTourist {
to_visit: Vec<PathBuf>,
to_skip: HashSet<PathBuf>,
pub errors: Vec<std::io::Error>,
filter: IgnoreFilterer,
}
#[derive(Debug)]
@ -360,13 +341,23 @@ enum Visit {
}
impl DirTourist {
pub fn new(base: PathBuf) -> Self {
Self {
pub async fn new(base: &Path, files: &[IgnoreFile]) -> Result<Self, Error> {
let base = dunce::canonicalize(base)?;
trace!("create IgnoreFilterer for visiting directories");
let mut filter = IgnoreFilterer::new(&base, files)
.await
.map_err(|err| Error::new(ErrorKind::Other, err))?;
filter.add_globs(&["/.git", "/.hg", "/.bzr", "/_darcs", "/.fossil-settings"], Some(base.clone())).await
.map_err(|err| Error::new(ErrorKind::Other, err))?;
Ok(Self {
to_visit: vec![base.clone()],
base,
to_skip: HashSet::new(),
errors: Vec::new(),
}
filter,
})
}
pub async fn next(&mut self) -> Visit {
@ -377,6 +368,12 @@ impl DirTourist {
return Visit::Skip;
}
if !self.filter.check_dir(&path) {
trace!("path is ignored, adding to skip list");
self.skip(path);
return Visit::Skip;
}
let mut dir = match read_dir(&path).await {
Ok(dir) => dir,
Err(err) => {
@ -405,6 +402,12 @@ impl DirTourist {
match entry.file_type().await {
Ok(ft) => {
if ft.is_dir() {
if !self.filter.check_dir(&path) {
trace!("path is ignored, adding to skip list");
self.skip(path);
continue;
}
trace!("found a dir, adding to list");
self.to_visit.push(path);
} else {
@ -438,6 +441,18 @@ impl DirTourist {
self.to_skip.insert(path);
}
pub(crate) async fn add_last_file_to_filter(
&mut self,
files: &mut Vec<IgnoreFile>,
errors: &mut Vec<Error>,
) {
if let Some(ig) = files.last() {
if let Err(err) = self.filter.add_file(ig).await {
errors.push(Error::new(ErrorKind::Other, err));
}
}
}
fn must_skip(&self, mut path: &Path) -> bool {
if self.to_skip.contains(path) {
return true;
@ -455,17 +470,3 @@ impl DirTourist {
false
}
}
async fn add_last_file_to_filter(
filter: &mut Option<IgnoreFilterer>,
files: &mut Vec<IgnoreFile>,
errors: &mut Vec<Error>,
) {
if let Some(igf) = filter.as_mut() {
if let Some(ig) = files.last() {
if let Err(err) = igf.add_file(ig).await {
errors.push(Error::new(ErrorKind::Other, err));
}
}
}
}

View file

@ -145,6 +145,14 @@ impl IgnoreFilterer {
})?;
}
self.recompile(file.path.clone())?;
}
Ok(())
}
fn recompile(&mut self, file: PathBuf) -> Result<(), RuntimeError> {
if let Some(builder) = &mut self.builder {
let pre_ignores = self.compiled.num_ignores();
let pre_allows = self.compiled.num_whitelists();
@ -152,7 +160,7 @@ impl IgnoreFilterer {
let recompiled = builder
.build()
.map_err(|err| RuntimeError::IgnoreFileGlob {
file: file.path.clone(),
file,
err,
})?;
@ -167,6 +175,32 @@ impl IgnoreFilterer {
Ok(())
}
/// Adds some globs manually, if the builder is available.
///
/// Does nothing silently otherwise.
pub async fn add_globs(&mut self, globs: &[&str], applies_in: Option<PathBuf>) -> Result<(), RuntimeError> {
if let Some(ref mut builder) = self.builder {
let _span = trace_span!("loading ignore globs", ?globs).entered();
for line in globs {
if line.is_empty() || line.starts_with('#') {
continue;
}
trace!(?line, "adding ignore line");
builder
.add_line(applies_in.clone(), line)
.map_err(|err| RuntimeError::IgnoreFileGlob {
file: "manual glob".into(),
err,
})?;
}
self.recompile("manual glob".into())?;
}
Ok(())
}
/// Check a particular folder path against the ignore set.
///
/// Returns `false` if the folder should be ignored.