Skip to content

Commit d35a60e

Browse files
committed
pr: Add support for -D/--date-format parameter
1 parent 4878e65 commit d35a60e

File tree

4 files changed

+73
-12
lines changed

4 files changed

+73
-12
lines changed

src/uu/pr/locales/en-US.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pr-help-pages = Begin and stop printing with page FIRST_PAGE[:LAST_PAGE]
1313
pr-help-header =
1414
Use the string header to replace the file name
1515
in the header line.
16+
pr-help-date-format =
17+
Use 'date'-style FORMAT for the header date.
1618
pr-help-double-space =
1719
Produce output that is double spaced. An extra <newline>
1820
character is output following every <newline> found in the input.

src/uu/pr/locales/fr-FR.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pr-help-pages = Commencer et arrêter l'impression à la page PREMIÈRE_PAGE[:DE
1313
pr-help-header =
1414
Utiliser la chaîne d'en-tête pour remplacer le nom de fichier
1515
dans la ligne d'en-tête.
16+
pr-help-date-format =
17+
Utiliser le FORMAT de style 'date' pour la date dans la ligne d'en-tête.
1618
pr-help-double-space =
1719
Produire une sortie avec double espacement. Un caractère <saut de ligne>
1820
supplémentaire est affiché après chaque <saut de ligne> trouvé dans l'entrée.

src/uu/pr/src/pr.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use thiserror::Error;
1919
use uucore::display::Quotable;
2020
use uucore::error::UResult;
2121
use uucore::format_usage;
22-
use uucore::translate;
2322
use uucore::time::{FormatSystemTimeFallback, format, format_system_time};
23+
use uucore::translate;
2424

2525
const TAB: char = '\t';
2626
const LINES_PER_PAGE: usize = 66;
@@ -36,6 +36,7 @@ const FF: u8 = 0x0C_u8;
3636

3737
mod options {
3838
pub const HEADER: &str = "header";
39+
pub const DATE_FORMAT: &str = "date-format";
3940
pub const DOUBLE_SPACE: &str = "double-space";
4041
pub const NUMBER_LINES: &str = "number-lines";
4142
pub const FIRST_LINE_NUMBER: &str = "first-line-number";
@@ -176,6 +177,13 @@ pub fn uu_app() -> Command {
176177
.help(translate!("pr-help-header"))
177178
.value_name("STRING"),
178179
)
180+
.arg(
181+
Arg::new(options::DATE_FORMAT)
182+
.short('D')
183+
.long(options::DATE_FORMAT)
184+
.value_name("FORMAT")
185+
.help(translate!("pr-help-date-format")),
186+
)
179187
.arg(
180188
Arg::new(options::DOUBLE_SPACE)
181189
.short('d')
@@ -401,16 +409,21 @@ fn parse_usize(matches: &ArgMatches, opt: &str) -> Option<Result<usize, PrError>
401409
.map(from_parse_error_to_pr_error)
402410
}
403411

404-
fn get_date_format() -> String {
405-
// Replicate behavior from GNU manual.
406-
if std::env::var("POSIXLY_CORRECT").is_ok()
407-
// TODO: This needs to be moved to uucore and handled by icu?
408-
&& (std::env::var("LC_TIME").unwrap_or_default() == "POSIX"
409-
|| std::env::var("LC_ALL").unwrap_or_default() == "POSIX")
410-
{
411-
"%b %e %H:%M %Y"
412-
} else {
413-
format::LONG_ISO
412+
fn get_date_format(matches: &ArgMatches) -> String {
413+
match matches.get_one::<String>(options::DATE_FORMAT) {
414+
Some(format) => format,
415+
None => {
416+
// Replicate behavior from GNU manual.
417+
if std::env::var("POSIXLY_CORRECT").is_ok()
418+
// TODO: This needs to be moved to uucore and handled by icu?
419+
&& (std::env::var("LC_TIME").unwrap_or_default() == "POSIX"
420+
|| std::env::var("LC_ALL").unwrap_or_default() == "POSIX")
421+
{
422+
"%b %e %H:%M %Y"
423+
} else {
424+
format::LONG_ISO
425+
}
426+
}
414427
}
415428
.to_string()
416429
}
@@ -514,7 +527,7 @@ fn build_options(
514527
format_system_time(
515528
&mut v,
516529
time,
517-
&get_date_format(),
530+
&get_date_format(matches),
518531
FormatSystemTimeFallback::Integer,
519532
)
520533
.ok()

tests/by-util/test_pr.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,50 @@ fn test_with_offset_space_option() {
404404

405405
#[test]
406406
fn test_with_date_format() {
407+
let test_file_path = "test_one_page.log";
408+
let expected_test_file_path = "test_one_page.log.expected";
409+
let mut scenario = new_ucmd!();
410+
let value = file_last_modified_time_format(&scenario, test_file_path, "%Y__%s");
411+
scenario
412+
.args(&[test_file_path, "-D", "%Y__%s"])
413+
.succeeds()
414+
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
415+
416+
// "Format" doesn't need to contain any replaceable token.
417+
let mut scenario = new_ucmd!();
418+
scenario
419+
.args(&[test_file_path, "-D", "Hello!"])
420+
.succeeds()
421+
.stdout_is_templated_fixture(
422+
expected_test_file_path,
423+
&[("{last_modified_time}", "Hello!")],
424+
);
425+
426+
// Long option also works
427+
let mut scenario = new_ucmd!();
428+
scenario
429+
.args(&[test_file_path, "--date-format=Hello!"])
430+
.succeeds()
431+
.stdout_is_templated_fixture(
432+
expected_test_file_path,
433+
&[("{last_modified_time}", "Hello!")],
434+
);
435+
436+
// Option takes precedence over environment variables
437+
let mut scenario = new_ucmd!();
438+
scenario
439+
.env("POSIXLY_CORRECT", "1")
440+
.env("LC_TIME", "POSIX")
441+
.args(&[test_file_path, "-D", "Hello!"])
442+
.succeeds()
443+
.stdout_is_templated_fixture(
444+
expected_test_file_path,
445+
&[("{last_modified_time}", "Hello!")],
446+
);
447+
}
448+
449+
#[test]
450+
fn test_with_date_format_env() {
407451
const POSIXLY_FORMAT: &str = "%b %e %H:%M %Y";
408452

409453
// POSIXLY_CORRECT + LC_ALL/TIME=POSIX uses "%b %e %H:%M %Y" date format

0 commit comments

Comments
 (0)