mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-07 05:16:33 +00:00
gitignore: fix prefix handling when chaining .gitignore in sub directory
The prefix is relative to the root, not to the parent .gitignore file. Fixes #3126
This commit is contained in:
parent
2f25848883
commit
febae9f9e8
1 changed files with 29 additions and 7 deletions
|
@ -39,29 +39,30 @@ pub enum GitIgnoreError {
|
||||||
/// Models the effective contents of multiple .gitignore files.
|
/// Models the effective contents of multiple .gitignore files.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GitIgnoreFile {
|
pub struct GitIgnoreFile {
|
||||||
path: String,
|
|
||||||
matchers: Vec<gitignore::Gitignore>,
|
matchers: Vec<gitignore::Gitignore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GitIgnoreFile {
|
impl GitIgnoreFile {
|
||||||
pub fn empty() -> Arc<GitIgnoreFile> {
|
pub fn empty() -> Arc<GitIgnoreFile> {
|
||||||
Arc::new(GitIgnoreFile {
|
Arc::new(GitIgnoreFile {
|
||||||
path: Default::default(),
|
|
||||||
matchers: 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(
|
pub fn chain(
|
||||||
self: &Arc<GitIgnoreFile>,
|
self: &Arc<GitIgnoreFile>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
) -> Result<Arc<GitIgnoreFile>, GitIgnoreError> {
|
) -> Result<Arc<GitIgnoreFile>, GitIgnoreError> {
|
||||||
let path = self.path.clone() + prefix;
|
let mut builder = gitignore::GitignoreBuilder::new(prefix);
|
||||||
let mut builder = gitignore::GitignoreBuilder::new(&path);
|
|
||||||
for (i, input_line) in input.split(|b| *b == b'\n').enumerate() {
|
for (i, input_line) in input.split(|b| *b == b'\n').enumerate() {
|
||||||
let line =
|
let line =
|
||||||
std::str::from_utf8(input_line).map_err(|err| GitIgnoreError::InvalidUtf8 {
|
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_num_for_display: i + 1,
|
||||||
line: String::from_utf8_lossy(input_line).to_string(),
|
line: String::from_utf8_lossy(input_line).to_string(),
|
||||||
source: err,
|
source: err,
|
||||||
|
@ -74,9 +75,13 @@ impl GitIgnoreFile {
|
||||||
let mut matchers = self.matchers.clone();
|
let mut matchers = self.matchers.clone();
|
||||||
matchers.push(matcher);
|
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(
|
pub fn chain_with_file(
|
||||||
self: &Arc<GitIgnoreFile>,
|
self: &Arc<GitIgnoreFile>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
|
@ -199,6 +204,23 @@ mod tests {
|
||||||
assert!(file.matches("dir1/dir2/dir3/dir4/foo"));
|
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]
|
#[test]
|
||||||
fn test_gitignore_match_only_dir() {
|
fn test_gitignore_match_only_dir() {
|
||||||
let file = GitIgnoreFile::empty().chain("", b"/dir/\n").unwrap();
|
let file = GitIgnoreFile::empty().chain("", b"/dir/\n").unwrap();
|
||||||
|
@ -362,7 +384,7 @@ mod tests {
|
||||||
assert!(!file2.matches("foo/bar"));
|
assert!(!file2.matches("foo/bar"));
|
||||||
assert!(!file2.matches("foo/bar/baz"));
|
assert!(!file2.matches("foo/bar/baz"));
|
||||||
assert!(file2.matches("foo/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"));
|
assert!(!file3.matches("foo/bar/qux"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue