Skip to content

Commit 4ef879e

Browse files
committed
refactor
1 parent ff43946 commit 4ef879e

File tree

4 files changed

+131
-121
lines changed

4 files changed

+131
-121
lines changed

gix-attributes/src/match_group.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ pub enum Value {
6161
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Default)]
6262
pub struct Attributes;
6363

64+
fn macro_mode() -> gix_glob::pattern::Mode {
65+
gix_glob::pattern::Mode::all()
66+
}
67+
6468
impl Pattern for Attributes {
6569
type Value = Value;
6670

@@ -72,7 +76,7 @@ impl Pattern for Attributes {
7276
crate::parse::Kind::Macro(macro_name) => (
7377
gix_glob::Pattern {
7478
text: macro_name.as_str().into(),
75-
mode: gix_glob::pattern::Mode::all(),
79+
mode: macro_mode(),
7680
first_wildcard_pos: None,
7781
},
7882
Value::MacroAttributes(into_owned_assignments(assignments).ok()?),
@@ -93,7 +97,7 @@ impl Pattern for Attributes {
9397
}
9498

9599
fn may_use_glob_pattern(pattern: &gix_glob::Pattern) -> bool {
96-
pattern.mode != gix_glob::pattern::Mode::all()
100+
pattern.mode != macro_mode()
97101
}
98102
}
99103

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use std::io::Read;
2+
3+
use bstr::{BStr, ByteSlice};
4+
use gix_attributes::{Ignore, Match, MatchGroup};
5+
use gix_glob::pattern::Case;
6+
7+
struct Expectations<'a> {
8+
lines: bstr::Lines<'a>,
9+
}
10+
11+
impl<'a> Iterator for Expectations<'a> {
12+
type Item = (&'a BStr, Option<(&'a BStr, usize, &'a BStr)>);
13+
14+
fn next(&mut self) -> Option<Self::Item> {
15+
let line = self.lines.next()?;
16+
let (left, value) = line.split_at(line.find_byte(b'\t').unwrap());
17+
let value = value[1..].as_bstr();
18+
19+
let source_and_line = if left == b"::" {
20+
None
21+
} else {
22+
let mut tokens = left.split(|b| *b == b':');
23+
let source = tokens.next().unwrap().as_bstr();
24+
let line_number: usize = tokens.next().unwrap().to_str_lossy().parse().ok().unwrap();
25+
let pattern = tokens.next().unwrap().as_bstr();
26+
Some((source, line_number, pattern))
27+
};
28+
Some((value, source_and_line))
29+
}
30+
}
31+
32+
#[test]
33+
fn from_git_dir() -> crate::Result {
34+
let dir = gix_testtools::scripted_fixture_read_only("make_global_and_external_and_dir_ignores.sh")?;
35+
let repo_dir = dir.join("repo");
36+
let git_dir = repo_dir.join(".git");
37+
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
38+
let mut buf = Vec::new();
39+
let mut group = MatchGroup::from_git_dir(git_dir, Some(dir.join("user.exclude")), &mut buf)?;
40+
41+
assert!(
42+
!group.add_patterns_file("not-a-file", false, None, &mut buf)?,
43+
"missing files are no problem and cause a negative response"
44+
);
45+
assert!(
46+
group.add_patterns_file(repo_dir.join(".gitignore"), true, repo_dir.as_path().into(), &mut buf)?,
47+
"existing files return true"
48+
);
49+
50+
buf.clear();
51+
let ignore_file = repo_dir.join("dir-with-ignore").join(".gitignore");
52+
std::fs::File::open(&ignore_file)?.read_to_end(&mut buf)?;
53+
group.add_patterns_buffer(&buf, ignore_file, repo_dir.as_path().into());
54+
55+
for (path, source_and_line) in (Expectations {
56+
lines: baseline.lines(),
57+
}) {
58+
let actual = group.pattern_matching_relative_path(
59+
path,
60+
repo_dir
61+
.join(path.to_str_lossy().as_ref())
62+
.metadata()
63+
.ok()
64+
.map(|m| m.is_dir()),
65+
Case::Sensitive,
66+
);
67+
match (actual, source_and_line) {
68+
(
69+
Some(Match {
70+
sequence_number,
71+
pattern: _,
72+
source,
73+
value: _,
74+
}),
75+
Some((expected_source, line, _expected_pattern)),
76+
) => {
77+
assert_eq!(sequence_number, line, "our counting should match the one used in git");
78+
assert_eq!(
79+
source.map(|p| p.canonicalize().unwrap()),
80+
Some(repo_dir.join(expected_source.to_str_lossy().as_ref()).canonicalize()?)
81+
);
82+
}
83+
(None, None) => {}
84+
(actual, expected) => panic!("actual {actual:?} should match {expected:?} with path '{path}'"),
85+
}
86+
}
87+
Ok(())
88+
}
89+
90+
#[test]
91+
fn from_overrides() {
92+
let input = ["simple", "pattern/"];
93+
let group = gix_attributes::MatchGroup::<Ignore>::from_overrides(input);
94+
assert_eq!(
95+
group.pattern_matching_relative_path("Simple", None, gix_glob::pattern::Case::Fold),
96+
Some(pattern_to_match(&gix_glob::parse("simple").unwrap(), 0))
97+
);
98+
assert_eq!(
99+
group.pattern_matching_relative_path("pattern", Some(true), gix_glob::pattern::Case::Sensitive),
100+
Some(pattern_to_match(&gix_glob::parse("pattern/").unwrap(), 1))
101+
);
102+
assert_eq!(group.patterns.len(), 1);
103+
assert_eq!(
104+
gix_attributes::PatternList::<Ignore>::from_overrides(input),
105+
group.patterns.into_iter().next().unwrap()
106+
);
107+
}
108+
109+
fn pattern_to_match(pattern: &gix_glob::Pattern, sequence_number: usize) -> Match<'_, ()> {
110+
Match {
111+
pattern,
112+
value: &(),
113+
source: None,
114+
sequence_number,
115+
}
116+
}
Lines changed: 1 addition & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1 @@
1-
mod ignore {
2-
use std::io::Read;
3-
4-
use bstr::{BStr, ByteSlice};
5-
use gix_attributes::{Ignore, Match, MatchGroup};
6-
use gix_glob::pattern::Case;
7-
8-
struct Expectations<'a> {
9-
lines: bstr::Lines<'a>,
10-
}
11-
12-
impl<'a> Iterator for Expectations<'a> {
13-
type Item = (&'a BStr, Option<(&'a BStr, usize, &'a BStr)>);
14-
15-
fn next(&mut self) -> Option<Self::Item> {
16-
let line = self.lines.next()?;
17-
let (left, value) = line.split_at(line.find_byte(b'\t').unwrap());
18-
let value = value[1..].as_bstr();
19-
20-
let source_and_line = if left == b"::" {
21-
None
22-
} else {
23-
let mut tokens = left.split(|b| *b == b':');
24-
let source = tokens.next().unwrap().as_bstr();
25-
let line_number: usize = tokens.next().unwrap().to_str_lossy().parse().ok().unwrap();
26-
let pattern = tokens.next().unwrap().as_bstr();
27-
Some((source, line_number, pattern))
28-
};
29-
Some((value, source_and_line))
30-
}
31-
}
32-
33-
#[test]
34-
fn from_git_dir() -> crate::Result {
35-
let dir = gix_testtools::scripted_fixture_read_only("make_global_and_external_and_dir_ignores.sh")?;
36-
let repo_dir = dir.join("repo");
37-
let git_dir = repo_dir.join(".git");
38-
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
39-
let mut buf = Vec::new();
40-
let mut group = MatchGroup::from_git_dir(git_dir, Some(dir.join("user.exclude")), &mut buf)?;
41-
42-
assert!(
43-
!group.add_patterns_file("not-a-file", false, None, &mut buf)?,
44-
"missing files are no problem and cause a negative response"
45-
);
46-
assert!(
47-
group.add_patterns_file(repo_dir.join(".gitignore"), true, repo_dir.as_path().into(), &mut buf)?,
48-
"existing files return true"
49-
);
50-
51-
buf.clear();
52-
let ignore_file = repo_dir.join("dir-with-ignore").join(".gitignore");
53-
std::fs::File::open(&ignore_file)?.read_to_end(&mut buf)?;
54-
group.add_patterns_buffer(&buf, ignore_file, repo_dir.as_path().into());
55-
56-
for (path, source_and_line) in (Expectations {
57-
lines: baseline.lines(),
58-
}) {
59-
let actual = group.pattern_matching_relative_path(
60-
path,
61-
repo_dir
62-
.join(path.to_str_lossy().as_ref())
63-
.metadata()
64-
.ok()
65-
.map(|m| m.is_dir()),
66-
Case::Sensitive,
67-
);
68-
match (actual, source_and_line) {
69-
(
70-
Some(Match {
71-
sequence_number,
72-
pattern: _,
73-
source,
74-
value: _,
75-
}),
76-
Some((expected_source, line, _expected_pattern)),
77-
) => {
78-
assert_eq!(sequence_number, line, "our counting should match the one used in git");
79-
assert_eq!(
80-
source.map(|p| p.canonicalize().unwrap()),
81-
Some(repo_dir.join(expected_source.to_str_lossy().as_ref()).canonicalize()?)
82-
);
83-
}
84-
(None, None) => {}
85-
(actual, expected) => panic!("actual {actual:?} should match {expected:?} with path '{path}'"),
86-
}
87-
}
88-
Ok(())
89-
}
90-
91-
#[test]
92-
fn from_overrides() {
93-
let input = ["simple", "pattern/"];
94-
let group = gix_attributes::MatchGroup::<Ignore>::from_overrides(input);
95-
assert_eq!(
96-
group.pattern_matching_relative_path("Simple", None, gix_glob::pattern::Case::Fold),
97-
Some(pattern_to_match(&gix_glob::parse("simple").unwrap(), 0))
98-
);
99-
assert_eq!(
100-
group.pattern_matching_relative_path("pattern", Some(true), gix_glob::pattern::Case::Sensitive),
101-
Some(pattern_to_match(&gix_glob::parse("pattern/").unwrap(), 1))
102-
);
103-
assert_eq!(group.patterns.len(), 1);
104-
assert_eq!(
105-
gix_attributes::PatternList::<Ignore>::from_overrides(input),
106-
group.patterns.into_iter().next().unwrap()
107-
);
108-
}
109-
110-
fn pattern_to_match(pattern: &gix_glob::Pattern, sequence_number: usize) -> Match<'_, ()> {
111-
Match {
112-
pattern,
113-
value: &(),
114-
source: None,
115-
sequence_number,
116-
}
117-
}
118-
}
1+
mod ignore;

gix/src/worktree/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,14 @@ pub mod excludes {
120120
/// Configure a file-system cache checking if files below the repository are excluded.
121121
///
122122
/// This takes into consideration all the usual repository configuration.
123-
// TODO: test, provide higher-level interface that is much easier to use and doesn't panic.
123+
///
124+
/// `index` may be used to obtain `.gitignore` files directly from the index under certain conditions.
125+
// TODO: test, provide higher-level interface that is much easier to use and doesn't panic when accessing entries
126+
// by non-relative path.
127+
// TODO: `index` might be so special (given the conditions we are talking about) that it's better obtained internally
128+
// so the caller won't have to care.
129+
// TODO: global files like `~/.gitignore` seem to be missing here, but we need a way to control if these should be loaded.
130+
// probably that needs another permission in the repo options or a custom config variable. The latter is easiest to manage.
124131
pub fn excludes(
125132
&self,
126133
index: &gix_index::State,

0 commit comments

Comments
 (0)