Skip to content

Commit

Permalink
gitignore: fix prefix handling when chaining .gitignore in sub directory
Browse files Browse the repository at this point in the history
The prefix is relative to the root, not to the parent .gitignore file.

Fixes #3126
  • Loading branch information
yuja committed Feb 24, 2024
1 parent b71bd63 commit 23c1e9b
Showing 1 changed file with 29 additions and 7 deletions.
36 changes: 29 additions & 7 deletions lib/src/gitignore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,30 @@ pub enum GitIgnoreError {
/// Models the effective contents of multiple .gitignore files.
#[derive(Debug)]
pub struct GitIgnoreFile {
path: String,
matchers: Vec<gitignore::Gitignore>,
}

impl GitIgnoreFile {
pub fn empty() -> Arc<GitIgnoreFile> {
Arc::new(GitIgnoreFile {
path: Default::default(),
matchers: Default::default(),
})
}

/// Concatenates new `.gitignore` content at the `prefix` directory.
///
/// The `prefix` should be a slash-separated path relative to the workspace
/// root.
pub fn chain(
self: &Arc<GitIgnoreFile>,
prefix: &str,
input: &[u8],
) -> Result<Arc<GitIgnoreFile>, GitIgnoreError> {
let path = self.path.clone() + prefix;
let mut builder = gitignore::GitignoreBuilder::new(&path);
let mut builder = gitignore::GitignoreBuilder::new(prefix);
for (i, input_line) in input.split(|b| *b == b'\n').enumerate() {
let line =
std::str::from_utf8(input_line).map_err(|err| GitIgnoreError::InvalidUtf8 {
path: PathBuf::from(&path),
path: PathBuf::from(prefix),
line_num_for_display: i + 1,
line: String::from_utf8_lossy(input_line).to_string(),
source: err,
Expand All @@ -74,9 +75,13 @@ impl GitIgnoreFile {
let mut matchers = self.matchers.clone();
matchers.push(matcher);

Ok(Arc::new(GitIgnoreFile { path, matchers }))
Ok(Arc::new(GitIgnoreFile { matchers }))
}

/// Concatenates new `.gitignore` file at the `prefix` directory.
///
/// The `prefix` should be a slash-separated path relative to the workspace
/// root.
pub fn chain_with_file(
self: &Arc<GitIgnoreFile>,
prefix: &str,
Expand Down Expand Up @@ -199,6 +204,23 @@ mod tests {
assert!(file.matches("dir1/dir2/dir3/dir4/foo"));
}

#[test]
fn test_gitignore_deep_dir_chained() {
// Prefix is relative to root, not to parent file
let file = GitIgnoreFile::empty()
.chain("", b"/dummy\n")
.unwrap()
.chain("dir1/", b"/dummy\n")
.unwrap()
.chain("dir1/dir2/", b"/dir3\n")
.unwrap();
assert!(!file.matches("foo"));
assert!(!file.matches("dir1/foo"));
assert!(!file.matches("dir1/dir2/foo"));
assert!(file.matches("dir1/dir2/dir3/foo"));
assert!(file.matches("dir1/dir2/dir3/dir4/foo"));
}

#[test]
fn test_gitignore_match_only_dir() {
let file = GitIgnoreFile::empty().chain("", b"/dir/\n").unwrap();
Expand Down Expand Up @@ -362,7 +384,7 @@ mod tests {
assert!(!file2.matches("foo/bar"));
assert!(!file2.matches("foo/bar/baz"));
assert!(file2.matches("foo/baz"));
// FIXME: assert!(file3.matches("foo/bar/baz"));
assert!(file3.matches("foo/bar/baz"));
assert!(!file3.matches("foo/bar/qux"));
}

Expand Down

0 comments on commit 23c1e9b

Please sign in to comment.