Skip to content

Commit 5608270

Browse files
committed
Fix file open paths so it works from anywhere
When parsing `git ls-tree` output and opening the files we need to use the full path so it works from any directory. Also add various tests.
1 parent ed6a71a commit 5608270

File tree

4 files changed

+83
-9
lines changed

4 files changed

+83
-9
lines changed

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,6 @@ members = [
5858
"lints/lint_tabs",
5959
"lints/lint_whitespace",
6060
]
61+
62+
[dev-dependencies]
63+
tempfile = "3.19.1"

src/file_matching.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,24 @@ pub fn matching_files<'a>(files: &'a [FileInfo], expr: &MatchExpression) -> Vec<
5858
pub fn retain_matching_files<'a>(files: &mut Vec<FileInfo>, expr: &MatchExpression) {
5959
files.retain(|f| file_matches(f, expr))
6060
}
61+
62+
#[cfg(test)]
63+
mod test {
64+
use super::*;
65+
use crate::git::FileType;
66+
67+
#[test]
68+
fn test_matching_files() {
69+
let files = vec![
70+
FileInfo {
71+
path: "foo.rs".into(),
72+
ty: FileType::Text,
73+
shebang: None,
74+
}
75+
];
76+
77+
let expr = MatchExpression::Glob(glob::Pattern::new("*.rs").unwrap());
78+
let matches = matching_files(&files, &expr);
79+
assert_eq!(matches.len(), 1);
80+
}
81+
}

src/git.rs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn git_hooks_dir() -> Result<PathBuf> {
2828
Ok(PathBuf::from(path.trim()))
2929
}
3030

31-
#[derive(Debug, Deserialize, Eq, PartialEq)]
31+
#[derive(Debug, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
3232
#[serde(rename_all = "snake_case")]
3333
pub enum FileType {
3434
Symlink,
@@ -42,6 +42,7 @@ pub enum FileType {
4242
Binary,
4343
}
4444

45+
#[derive(Eq, PartialEq, Ord, PartialOrd)]
4546
pub struct FileInfo {
4647
pub path: PathBuf,
4748
pub ty: FileType,
@@ -82,7 +83,7 @@ pub fn git_tree_files(top_level: &Path, treeish: &str) -> Result<Vec<FileInfo>>
8283
bail!("git ls-tree command failed");
8384
}
8485

85-
process_file_info(&command.stdout)
86+
process_file_info(top_level, &command.stdout)
8687
}
8788

8889
/// Get info on all of the staged files.
@@ -105,7 +106,7 @@ pub fn git_staged_files(top_level: &Path) -> Result<Vec<FileInfo>> {
105106
bail!("git ls-files command failed");
106107
}
107108

108-
process_file_info(&command.stdout)
109+
process_file_info(top_level, &command.stdout)
109110
}
110111

111112
/// List of files changed in the working directory (not staged).
@@ -125,7 +126,7 @@ pub fn git_diff_unstaged(top_level: &Path) -> Result<Vec<u8>> {
125126
Ok(output.stdout)
126127
}
127128

128-
fn process_file_info(ls_files_stdout: &[u8]) -> Result<Vec<FileInfo>> {
129+
fn process_file_info(top_level: &Path, ls_files_stdout: &[u8]) -> Result<Vec<FileInfo>> {
129130
ls_files_stdout
130131
.split(|&b| b == 0)
131132
.tuples()
@@ -149,7 +150,8 @@ fn process_file_info(ls_files_stdout: &[u8]) -> Result<Vec<FileInfo>> {
149150
} else {
150151
// Read the first 8000 bytes and look for a null byte. This is how
151152
// Git decides if it's binary.
152-
let mut file = std::fs::File::open(&path)?;
153+
let full_path = top_level.join(path);
154+
let mut file = std::fs::File::open(&full_path)?;
153155
let mut buf = [0; 8000];
154156
let len = read_up_to(&mut file, &mut buf)?;
155157
let contents = &buf[..len];
@@ -214,3 +216,51 @@ fn read_up_to(file: &mut impl std::io::Read, mut buf: &mut [u8]) -> Result<usize
214216
}
215217
Ok(buf_len - buf.len())
216218
}
219+
220+
221+
#[cfg(test)]
222+
mod test {
223+
use super::*;
224+
use tempfile::tempdir;
225+
226+
#[test]
227+
fn test_process_file_info() {
228+
let dir = tempdir().expect("Failed to create temp dir");
229+
230+
let text_path = dir.path().join("test.txt");
231+
std::fs::write(&text_path, "Hello, world!").expect("Failed to write test text file");
232+
let bin_path = dir.path().join("test.bin");
233+
std::fs::write(&bin_path, b"Hello \x00!").expect("Failed to write test binary file");
234+
235+
let output = Command::new("git")
236+
.arg("init")
237+
.current_dir(dir.path())
238+
.output()
239+
.expect("Failed to run git init");
240+
assert!(output.status.success());
241+
242+
let output = Command::new("git")
243+
.arg("add")
244+
.arg(&text_path)
245+
.arg(&bin_path)
246+
.current_dir(dir.path())
247+
.output()
248+
.expect("Failed to run git add");
249+
assert!(output.status.success());
250+
251+
let output = Command::new("git")
252+
.arg("commit")
253+
.arg("-m")
254+
.arg("Test commit")
255+
.current_dir(dir.path())
256+
.output()
257+
.expect("Failed to run git commit");
258+
assert!(output.status.success());
259+
260+
let mut files = git_tree_files(dir.path(), "HEAD").expect("Failed to get git tree files");
261+
files.sort();
262+
assert_eq!(files.len(), 2);
263+
assert_eq!(files[0].ty, FileType::Binary);
264+
assert_eq!(files[1].ty, FileType::Text);
265+
}
266+
}

0 commit comments

Comments
 (0)