Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ff98e6d
copy `ignore` crate for easier modifications
RobinMalfait Mar 17, 2025
18442be
manually apply patches to inlined `ignore` crate
RobinMalfait Mar 17, 2025
22bd00f
run all CI tests when `[ci-all]` exists in PR description
RobinMalfait Mar 21, 2025
ba153be
big refactor, move `Scanner` to `scanner/mod.rs`
RobinMalfait Mar 21, 2025
72b18cd
simplify `scanner` test setup
RobinMalfait Mar 21, 2025
cd6ccb2
add new Scanner tests
RobinMalfait Mar 21, 2025
324569c
update public Rust API
RobinMalfait Mar 21, 2025
335e9e1
update use statements due to big refactor
RobinMalfait Mar 21, 2025
88a6048
rename `globs` to `sources`
RobinMalfait Mar 21, 2025
602a801
add `negated` flag to `sources`
RobinMalfait Mar 21, 2025
9798637
add missing `reference` property
RobinMalfait Mar 21, 2025
9958612
update integration tests
RobinMalfait Mar 21, 2025
878782e
use `normalizedSources` in the CLI
RobinMalfait Mar 21, 2025
a7bef4e
add `.gitignore` as a default ignored file
RobinMalfait Mar 21, 2025
8d154d1
add `node_modules` as a default ignored folder
RobinMalfait Mar 21, 2025
38ed37e
add `enableSourceNot` feature flag
RobinMalfait Mar 21, 2025
0f73797
run prettier
RobinMalfait Mar 21, 2025
97fc4bf
Simplify gitignore order change
philipp-spiess Mar 25, 2025
94473d3
Rename GitHub CI var
philipp-spiess Mar 25, 2025
7442baa
Explicitly mark test functions
philipp-spiess Mar 25, 2025
2425aef
Handle source paths into ignored content dirs as "external"
philipp-spiess Mar 25, 2025
bb0610d
Revert "Explicitly mark test functions"
philipp-spiess Mar 25, 2025
6952871
Explicitly mark test functions
philipp-spiess Mar 25, 2025
b6ab98f
Cleanup comment
philipp-spiess Mar 25, 2025
5e7d035
Cleanup public source entry creation
philipp-spiess Mar 25, 2025
9d4c2af
Cleanups and test utf8 special characters in paths
philipp-spiess Mar 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
manually apply patches to inlined ignore crate
  • Loading branch information
RobinMalfait authored and philipp-spiess committed Mar 25, 2025
commit 18442bebae6b5db55226229bec0ba28e68ca7ae9
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/ignore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ bench = false

[dependencies]
crossbeam-deque = "0.8.3"
globset = "0.4.15"
globset = "0.4.16"
log = "0.4.20"
memchr = "2.6.3"
same-file = "1.0.6"
walkdir = "2.4.0"
dunce = "1.0.5"

[dependencies.regex-automata]
version = "0.4.0"
Expand Down
154 changes: 86 additions & 68 deletions crates/ignore/src/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ impl Ignore {
if !self.is_root() {
panic!("Ignore::add_parents called on non-root matcher");
}
let absolute_base = match path.as_ref().canonicalize() {
// CHANGED: Use `dunce::canonicalize` as we use it everywhere else.
let absolute_base = match dunce::canonicalize(path.as_ref()) {
Ok(path) => Arc::new(path),
Err(_) => {
// There's not much we can do here, so just return our
Expand Down Expand Up @@ -428,60 +429,51 @@ impl Ignore {
saw_git = saw_git || ig.0.has_git;
}
if self.0.opts.parents {
if let Some(abs_parent_path) = self.absolute_base() {
// What we want to do here is take the absolute base path of
// this directory and join it with the path we're searching.
// The main issue we want to avoid is accidentally duplicating
// directory components, so we try to strip any common prefix
// off of `path`. Overall, this seems a little ham-fisted, but
// it does fix a nasty bug. It should do fine until we overhaul
// this crate.
let dirpath = self.0.dir.as_path();
let path_prefix = match strip_prefix("./", dirpath) {
None => dirpath,
Some(stripped_dot_slash) => stripped_dot_slash,
};
let path = match strip_prefix(path_prefix, path) {
None => abs_parent_path.join(path),
Some(p) => {
let p = match strip_prefix("/", p) {
None => p,
Some(p) => p,
};
abs_parent_path.join(p)
}
};

for ig in self.parents().skip_while(|ig| !ig.0.is_absolute_parent) {
if m_custom_ignore.is_none() {
m_custom_ignore =
ig.0.custom_ignore_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
if m_ignore.is_none() {
m_ignore =
ig.0.ignore_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
if any_git && !saw_git && m_gi.is_none() {
m_gi =
ig.0.git_ignore_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
if any_git && !saw_git && m_gi_exclude.is_none() {
m_gi_exclude =
ig.0.git_exclude_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
saw_git = saw_git || ig.0.has_git;
// CHANGED: We removed a code path that rewrote the `path` to be relative to
// `self.absolute_base()` because it assumed that the every path is inside the base
// which is not the case for us as we use `WalkBuilder#add` to add roots outside of the
// base.
for ig in self.parents().skip_while(|ig| !ig.0.is_absolute_parent) {
if m_custom_ignore.is_none() {
m_custom_ignore =
ig.0.custom_ignore_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
if m_ignore.is_none() {
m_ignore =
ig.0.ignore_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
if any_git && !saw_git && m_gi.is_none() {
m_gi =
ig.0.git_ignore_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
if any_git && !saw_git && m_gi_exclude.is_none() {
m_gi_exclude =
ig.0.git_exclude_matcher
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
}
saw_git = saw_git || ig.0.has_git;
}
}
for gi in self.0.explicit_ignores.iter().rev() {
// CHANGED: We need to make sure that the explicit gitignore rules apply to the path
//
// path = Is the current file/folder we are traversing
// gi.path() = Is the path of the custom gitignore file
//
// E.g.: If we have a custom rule for `/src/utils` with `**/*`, and we are looking at
// just `/src`, then the `**/*` rules do not apply to this folder, so we can
// ignore the current custom gitignore file.
//
if !path.starts_with(gi.path()) {
continue;
}
if !m_explicit.is_none() {
break;
}
Expand All @@ -496,24 +488,47 @@ impl Ignore {
Match::None
};

m_custom_ignore
.or(m_ignore)
.or(m_gi)
.or(m_gi_exclude)
.or(m_global)
.or(m_explicit)
// CHANGED: We added logic to configure an order in which the ignore files are respected and
// allowed a whitelist in a later file to overrule a block on an earlier file.
let order = [
// Global gitignore
&m_global,
// .git/info/exclude
&m_gi_exclude,
// .gitignore
&m_gi,
// .ignore
&m_ignore,
// .custom-ignore
&m_custom_ignore,
// Manually added ignores
&m_explicit,
];

for (idx, check) in order.into_iter().enumerate() {
if check.is_none() {
continue;
}

let remaining = &order[idx + 1..];
if check.is_ignore() {
if remaining.iter().any(|other| other.is_whitelist()) {
continue;
}
} else if remaining.iter().any(|other| other.is_ignore()) {
continue;
}

return check.clone();
}

m_explicit
}

/// Returns an iterator over parent ignore matchers, including this one.
pub(crate) fn parents(&self) -> Parents<'_> {
Parents(Some(self))
}

/// Returns the first absolute path of the first absolute parent, if
/// one exists.
fn absolute_base(&self) -> Option<&Path> {
self.0.absolute_base.as_ref().map(|p| &***p)
}
}

/// An iterator over all parents of an ignore matcher, including itself.
Expand Down Expand Up @@ -875,9 +890,10 @@ mod tests {
.build()
.add_child(td.path());
assert!(err.is_none());
assert!(ig.matched("foo", false).is_ignore());
assert!(ig.matched("bar", false).is_whitelist());
assert!(ig.matched("baz", false).is_none());
assert!(ig.matched(td.path().join("foo"), false).is_ignore());
assert!(ig.matched(td.path().join("bar"), false).is_whitelist());
assert!(ig.matched(td.path().join("baz"), false).is_none());
assert!(ig.matched("/foo", false).is_none());
}

#[test]
Expand Down Expand Up @@ -1131,8 +1147,10 @@ mod tests {
let (ig2, err) = ig1.add_child("src");
assert!(err.is_none());

assert!(ig1.matched("llvm", true).is_none());
assert!(ig2.matched("llvm", true).is_none());
// CHANGED: These test cases do not make sense for us as we never call the Ignore with
// relative paths.
assert!(ig1.matched("llvm", true).is_ignore());
assert!(ig2.matched("llvm", true).is_ignore());
assert!(ig2.matched("src/llvm", true).is_none());
assert!(ig2.matched("foo", false).is_ignore());
assert!(ig2.matched("src/foo", false).is_ignore());
Expand Down
7 changes: 6 additions & 1 deletion crates/ignore/src/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use {

use crate::{
dir::{Ignore, IgnoreBuilder},
gitignore::GitignoreBuilder,
gitignore::{Gitignore, GitignoreBuilder},
overrides::Override,
types::Types,
Error, PartialErrorBuilder,
Expand Down Expand Up @@ -666,6 +666,11 @@ impl WalkBuilder {
errs.into_error_option()
}

/// CHANGED: Add a Gitignore to the builder.
pub fn add_gitignore(&mut self, gi: Gitignore) {
self.ig_builder.add_ignore(gi);
}

/// Add a custom ignore file name
///
/// These ignore files have higher precedence than all other ignore files.
Expand Down