Skip to content

Commit

Permalink
Implement -fprintf (#444)
Browse files Browse the repository at this point in the history
  • Loading branch information
hanbings authored Sep 21, 2024
1 parent 0549337 commit 27d95aa
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 20 deletions.
15 changes: 14 additions & 1 deletion src/find/matchers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ fn build_matcher_tree(
return Err(From::from(format!("missing argument to {}", args[i])));
}
i += 1;
Some(Printf::new(args[i])?.into_box())
Some(Printf::new(args[i], None)?.into_box())
}
"-fprint" => {
if i >= args.len() - 1 {
Expand All @@ -464,6 +464,19 @@ fn build_matcher_tree(
let file = get_or_create_file(args[i])?;
Some(Printer::new(PrintDelimiter::Newline, Some(file)).into_box())
}
"-fprintf" => {
if i >= args.len() - 2 {
return Err(From::from(format!("missing argument to {}", args[i])));
}

// Action: -fprintf file format
// Args + 1: output file path
// Args + 2: format string
i += 1;
let file = get_or_create_file(args[i])?;
i += 1;
Some(Printf::new(args[i], Some(file))?.into_box())
}
"-fprint0" => {
if i >= args.len() - 1 {
return Err(From::from(format!("missing argument to {}", args[i])));
Expand Down
46 changes: 27 additions & 19 deletions src/find/matchers/printf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use std::borrow::Cow;
use std::error::Error;
use std::fs;
use std::fs::{self, File};
use std::path::Path;
use std::time::SystemTime;
use std::{borrow::Cow, io::Write};

use chrono::{format::StrftimeItems, DateTime, Local};

Expand Down Expand Up @@ -571,20 +571,18 @@ fn format_directive<'entry>(
/// find's printf syntax.
pub struct Printf {
format: FormatString,
output_file: Option<File>,
}

impl Printf {
pub fn new(format: &str) -> Result<Self, Box<dyn Error>> {
pub fn new(format: &str, output_file: Option<File>) -> Result<Self, Box<dyn Error>> {
Ok(Self {
format: FormatString::parse(format)?,
output_file,
})
}
}

impl Matcher for Printf {
fn matches(&self, file_info: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
let mut out = matcher_io.deps.get_output().borrow_mut();

fn print(&self, file_info: &WalkEntry, mut out: impl Write) {
for component in &self.format.components {
match component {
FormatComponent::Literal(literal) => write!(out, "{literal}").unwrap(),
Expand Down Expand Up @@ -619,6 +617,16 @@ impl Matcher for Printf {
},
}
}
}
}

impl Matcher for Printf {
fn matches(&self, file_info: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
if let Some(file) = &self.output_file {
self.print(file_info, file);
} else {
self.print(file_info, &mut *matcher_io.deps.get_output().borrow_mut());
}

true
}
Expand Down Expand Up @@ -804,7 +812,7 @@ mod tests {
let file_info = get_dir_entry_for("test_data/simple", "abbbc");
let deps = FakeDependencies::new();

let matcher = Printf::new("%f,%7f,%-7f").unwrap();
let matcher = Printf::new("%f,%7f,%-7f", None).unwrap();
assert!(matcher.matches(&file_info, &mut deps.new_matcher_io()));
assert_eq!("abbbc, abbbc,abbbc ", deps.get_output_as_string());
}
Expand All @@ -814,7 +822,7 @@ mod tests {
let file_info = get_dir_entry_for("test_data/simple", "abbbc");
let deps = FakeDependencies::new();

let matcher = Printf::new("%h %H %p %P").unwrap();
let matcher = Printf::new("%h %H %p %P", None).unwrap();
assert!(matcher.matches(&file_info, &mut deps.new_matcher_io()));
assert_eq!(
format!(
Expand All @@ -833,7 +841,7 @@ mod tests {
let file_info = get_dir_entry_for("test_data/simple", "subdir/ABBBC");
let deps = FakeDependencies::new();

let matcher = Printf::new("%h %H %p %P").unwrap();
let matcher = Printf::new("%h %H %p %P", None).unwrap();
assert!(matcher.matches(&file_info, &mut deps.new_matcher_io()));
assert_eq!(
format!(
Expand All @@ -853,7 +861,7 @@ mod tests {
let file_info_2 = get_dir_entry_for("test_data/depth/1", "2/f2");
let deps = FakeDependencies::new();

let matcher = Printf::new("%d.").unwrap();
let matcher = Printf::new("%d.", None).unwrap();
assert!(matcher.matches(&file_info_1, &mut deps.new_matcher_io()));
assert!(matcher.matches(&file_info_2, &mut deps.new_matcher_io()));
assert_eq!("1.2.", deps.get_output_as_string());
Expand All @@ -865,7 +873,7 @@ mod tests {
let file_info_d = get_dir_entry_for("test_data/simple", "subdir");
let deps = FakeDependencies::new();

let matcher = Printf::new("%y").unwrap();
let matcher = Printf::new("%y", None).unwrap();
assert!(matcher.matches(&file_info_f, &mut deps.new_matcher_io()));
assert!(matcher.matches(&file_info_d, &mut deps.new_matcher_io()));
assert_eq!("fd", deps.get_output_as_string());
Expand Down Expand Up @@ -893,7 +901,7 @@ mod tests {
let socket_info = get_dir_entry_for(&temp_dir_path, socket_name);
let deps = FakeDependencies::new();

let matcher = Printf::new("%y").unwrap();
let matcher = Printf::new("%y", None).unwrap();
assert!(matcher.matches(&fifo_info, &mut deps.new_matcher_io()));
assert!(matcher.matches(&socket_info, &mut deps.new_matcher_io()));
assert_eq!("ps", deps.get_output_as_string());
Expand All @@ -904,7 +912,7 @@ mod tests {
let file_info = get_dir_entry_for("test_data/size", "512bytes");
let deps = FakeDependencies::new();

let matcher = Printf::new("%s").unwrap();
let matcher = Printf::new("%s", None).unwrap();
assert!(matcher.matches(&file_info, &mut deps.new_matcher_io()));
assert_eq!("512", deps.get_output_as_string());
}
Expand Down Expand Up @@ -986,7 +994,7 @@ mod tests {

let deps = FakeDependencies::new();

let matcher = Printf::new("%y %Y %l\n").unwrap();
let matcher = Printf::new("%y %Y %l\n", None).unwrap();
assert!(matcher.matches(&regular_file, &mut deps.new_matcher_io()));
assert!(matcher.matches(&link_f, &mut deps.new_matcher_io()));
assert!(matcher.matches(&link_d, &mut deps.new_matcher_io()));
Expand Down Expand Up @@ -1033,7 +1041,7 @@ mod tests {
let file_info = get_dir_entry_for(&temp_dir_path, new_file_name);
let deps = FakeDependencies::new();

let matcher = Printf::new("%t,%T@,%TF").unwrap();
let matcher = Printf::new("%t,%T@,%TF", None).unwrap();
assert!(matcher.matches(&file_info, &mut deps.new_matcher_io()));
assert_eq!(
format!(
Expand Down Expand Up @@ -1061,7 +1069,7 @@ mod tests {
let file_info = get_dir_entry_for(&temp_dir_path, new_file_name);
let deps = FakeDependencies::new();

let matcher = Printf::new("%u %U %g %G").unwrap();
let matcher = Printf::new("%u %U %g %G", None).unwrap();
assert!(matcher.matches(&file_info, &mut deps.new_matcher_io()));
assert_eq!(
format!("{user} {uid} {group} {gid}"),
Expand All @@ -1086,7 +1094,7 @@ mod tests {
let file_info = get_dir_entry_for(&temp_dir_path, new_file_name);
let deps = FakeDependencies::new();

let matcher = Printf::new("%m %M").unwrap();
let matcher = Printf::new("%m %M", None).unwrap();
assert!(matcher.matches(&file_info, &mut deps.new_matcher_io()));
assert_eq!("755 -rwxr-xr-x", deps.get_output_as_string());
}
Expand Down
18 changes: 18 additions & 0 deletions src/find/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,24 @@ mod tests {
);
}

#[test]
fn find_fprintf() {
let deps = FakeDependencies::new();
let rc = find_main(
&[
"find",
"./test_data/simple",
"-fprintf",
"test_data/find_fprintf",
"%h %H %p %P",
],
&deps,
);
assert_eq!(rc, 0);

let _ = fs::remove_file("test_data/find_fprintf");
}

#[test]
#[cfg(unix)]
fn test_ls() {
Expand Down
27 changes: 27 additions & 0 deletions tests/find_cmd_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,33 @@ fn find_follow() {
.stderr(predicate::str::is_empty());
}

#[test]
#[serial(working_dir)]
fn find_fprintf() {
let _ = fs::remove_file("test_data/find_fprintf");

Command::cargo_bin("find")
.expect("found binary")
.args([
"test_data/simple",
"-fprintf",
"test_data/find_fprintf",
"%h %H %p %P",
])
.assert()
.success()
.stdout(predicate::str::is_empty())
.stderr(predicate::str::is_empty());

// read test_data/find_fprintf
let mut f = File::open("test_data/find_fprintf").unwrap();
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();
assert!(contents.contains("test_data/simple"));

let _ = fs::remove_file("test_data/find_fprintf");
}

#[test]
#[serial(working_dir)]
fn find_ls() {
Expand Down

0 comments on commit 27d95aa

Please sign in to comment.