Skip to content

Commit 40d6915

Browse files
feat(cli): skip binary files in recursive mode (#104)
1 parent 8fb64b9 commit 40d6915

File tree

4 files changed

+48
-1
lines changed

4 files changed

+48
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ format and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
66

77
## [Unreleased]
88

9+
### Added
10+
- Skip binary files during recursive traversal
11+
912
## [0.1.6] - 2025-07-26
1013

1114
### Added

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ keepsorted --fix <path> # rewrite files in place (default)
3535
```
3636

3737
Use `--recursive` (`-r`) to process directories. Combine with `git ls-files` in
38-
CI to check only tracked files.
38+
CI to check only tracked files. Binary files are skipped automatically.
3939

4040
### Keywords
4141

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env bats
2+
3+
load './helpers.bash'
4+
5+
@test "recursive skips binary files" {
6+
mkdir "$TEST_TMPDIR/dir"
7+
cp "$FILES_DIR/generic/1_in.txt" "$TEST_TMPDIR/dir/file.txt"
8+
printf '\x00\xff\x00\xff' > "$TEST_TMPDIR/dir/binary.bin"
9+
10+
run_keepsorted --mode fix --recursive "$TEST_TMPDIR/dir"
11+
[ "$status" -eq "$EXIT_SUCCESS" ]
12+
diff "$FILES_DIR/generic/1_out.txt" "$TEST_TMPDIR/dir/file.txt"
13+
}

src/main.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,23 @@ fn main() {
227227
}
228228

229229
fn handle_file(path: &Path, features: &[Feature], mode: Mode, diff_command: Option<&str>) -> bool {
230+
match is_text_file(path) {
231+
Ok(true) => {}
232+
Ok(false) => {
233+
eprintln!("skipping binary file {}", path.display());
234+
return true;
235+
}
236+
Err(e) => {
237+
eprintln!(
238+
"{}: failed to read file {}: {}",
239+
env!("CARGO_PKG_NAME"),
240+
path.display(),
241+
e
242+
);
243+
process::exit(EXIT_RUNTIME_ERROR);
244+
}
245+
}
246+
230247
let feature_names: Vec<String> = features.iter().map(|f| f.as_str().to_string()).collect();
231248
let sorted = match process_file(path, feature_names) {
232249
Ok(s) => s,
@@ -369,3 +386,17 @@ fn collect_files(dir: &Path, out: &mut Vec<PathBuf>) -> io::Result<()> {
369386
}
370387
Ok(())
371388
}
389+
390+
fn is_text_file(path: &Path) -> io::Result<bool> {
391+
use std::fs::File;
392+
use std::io::Read;
393+
394+
let mut file = File::open(path)?;
395+
let mut buf = [0u8; 8192];
396+
let n = file.read(&mut buf)?;
397+
let slice = &buf[..n];
398+
if slice.contains(&0) {
399+
return Ok(false);
400+
}
401+
Ok(std::str::from_utf8(slice).is_ok())
402+
}

0 commit comments

Comments
 (0)