Skip to content

Commit

Permalink
add another test to learn how / behaves, and * + excludes (#1458)
Browse files Browse the repository at this point in the history
This is quite typical in the wild where there ignore files are used
as include lists, instead of exclude-lists.
  • Loading branch information
Byron committed Jul 23, 2024
1 parent 1267712 commit 4f67be4
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ a/b/*
z/x
EOF

mkdir repo;
git init -q repo;
(cd repo
git init -q
git config core.excludesFile ../user.exclude

cat <<EOF >.git/info/exclude
Expand Down Expand Up @@ -93,3 +92,70 @@ E/f
E/F
EOF
)

git init slash-and-excludes
(cd slash-and-excludes
cat <<EOF >.gitignore
# a lone slash does nothing
/
# a file that was never ignored to begin
!file
EOF

git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
file
a-file-not-mentioned-in-gitignore
EOF
)

git init slash-and-excludes-in-subdir
(cd slash-and-excludes-in-subdir
mkdir sub
(cd sub
cat <<EOF >.gitignore
# a lone slash does nothing
/
# a file that was never ignored to begin
!file
EOF
)
git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
sub/file
sub/a-file-not-mentioned-in-gitignore
a-file-not-mentioned-in-gitignore
EOF
)

git init star-and-excludes
(cd star-and-excludes
cat <<EOF >.gitignore
# everything is excluded by default
*
# And negations are used as an allow-list
!file
EOF

git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
file
a-file-not-mentioned-in-gitignore
EOF
)

git init star-and-excludes-in-subdir
(cd star-and-excludes-in-subdir
mkdir sub
(cd sub
cat <<EOF >.gitignore
# everything is excluded by default
*
# And negations are used as an allow-list
!file
EOF
)

git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
sub/file
sub/a-file-not-mentioned-in-gitignore
a-file-not-mentioned-in-gitignore
EOF
)
137 changes: 75 additions & 62 deletions gix-ignore/tests/search/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::io::Read;

use bstr::{BStr, ByteSlice};
use gix_glob::pattern::Case;
use gix_ignore::search::Match;
Expand Down Expand Up @@ -31,69 +29,84 @@ impl<'a> Iterator for Expectations<'a> {

#[test]
fn baseline_from_git_dir() -> crate::Result {
let case = if gix_fs::Capabilities::probe("../.git".as_ref()).ignore_case {
Case::Fold
} else {
Case::Sensitive
};
let dir = gix_testtools::scripted_fixture_read_only("make_global_and_external_and_dir_ignores.sh")?;
let repo_dir = dir.join("repo");
let git_dir = repo_dir.join(".git");
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
let mut buf = Vec::new();
let mut group = gix_ignore::Search::from_git_dir(&git_dir, Some(dir.join("user.exclude")), &mut buf)?;
for repo_name in [
"repo",
"slash-and-excludes",
"star-and-excludes-in-subdir",
"slash-and-excludes-in-subdir",
] {
let case = if gix_fs::Capabilities::probe("../.git".as_ref()).ignore_case {
Case::Fold
} else {
Case::Sensitive
};
let dir = gix_testtools::scripted_fixture_read_only("make_global_and_external_and_dir_ignores.sh")?;
let repo_dir = dir.join(repo_name);
let git_dir = repo_dir.join(".git");
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
let mut buf = Vec::new();
let user_exclude = dir.join("user.exclude");
let mut group =
gix_ignore::Search::from_git_dir(&git_dir, user_exclude.is_file().then_some(user_exclude), &mut buf)?;

assert!(
!gix_glob::search::add_patterns_file(&mut group.patterns, "not-a-file".into(), false, None, &mut buf)?,
"missing files are no problem and cause a negative response"
);
assert!(
gix_glob::search::add_patterns_file(
&mut group.patterns,
repo_dir.join(".gitignore"),
true,
repo_dir.as_path().into(),
&mut buf
)?,
"existing files return true"
);
assert!(
!gix_glob::search::add_patterns_file(&mut group.patterns, "not-a-file".into(), false, None, &mut buf)?,
"missing files are no problem and cause a negative response"
);
let mut ignore_file = repo_dir.join(".gitignore");
if !ignore_file.is_file() {
ignore_file.pop();
ignore_file.push("sub/.gitignore");
}
assert!(
gix_glob::search::add_patterns_file(
&mut group.patterns,
ignore_file,
true,
repo_dir.as_path().into(),
&mut buf
)?,
"existing files return true"
);

buf.clear();
let ignore_file = repo_dir.join("dir-with-ignore").join(".gitignore");
std::fs::File::open(&ignore_file)?.read_to_end(&mut buf)?;
group.add_patterns_buffer(&buf, ignore_file, repo_dir.as_path().into());
let ignore_file = repo_dir.join("dir-with-ignore").join(".gitignore");
if ignore_file.is_file() {
let buf = std::fs::read(&ignore_file)?;
group.add_patterns_buffer(&buf, ignore_file, repo_dir.as_path().into());
}

for (path, source_and_line) in (Expectations {
lines: baseline.lines(),
}) {
let actual = group.pattern_matching_relative_path(
path,
repo_dir
.join(path.to_str_lossy().as_ref())
.metadata()
.ok()
.map(|m| m.is_dir()),
case,
);
match (actual, source_and_line) {
(
Some(Match {
sequence_number,
pattern: _,
source,
kind: gix_ignore::Kind::Expendable,
}),
Some((expected_source, line, _expected_pattern)),
) => {
assert_eq!(sequence_number, line, "our counting should match the one used in git");
assert_eq!(
source.map(|p| p.canonicalize().unwrap()),
Some(repo_dir.join(expected_source.to_str_lossy().as_ref()).canonicalize()?)
);
}
(None, None) => {}
(actual, expected) => {
panic!("{case:?}: actual {actual:?} should match {expected:?} with path '{path}'")
for (path, source_and_line) in (Expectations {
lines: baseline.lines(),
}) {
let actual = group.pattern_matching_relative_path(
path,
repo_dir
.join(path.to_str_lossy().as_ref())
.metadata()
.ok()
.map(|m| m.is_dir()),
case,
);
match (actual, source_and_line) {
(
Some(Match {
sequence_number,
pattern: _,
source,
kind: gix_ignore::Kind::Expendable,
}),
Some((expected_source, line, _expected_pattern)),
) => {
assert_eq!(sequence_number, line, "our counting should match the one used in git");
assert_eq!(
source.map(|p| p.canonicalize().unwrap()),
Some(repo_dir.join(expected_source.to_str_lossy().as_ref()).canonicalize()?)
);
}
(None, None) => {}
(actual, expected) => {
panic!("{repo_name}: {case:?}: actual {actual:?} should match {expected:?} with path '{path}'")
}
}
}
}
Expand Down

0 comments on commit 4f67be4

Please sign in to comment.