mirror of
https://github.com/uutils/diffutils.git
synced 2026-06-10 15:48:59 -07:00
Display modification times of input files in unified diff
This commit is contained in:
+1
-18
@@ -8,6 +8,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
use crate::params::Params;
|
use crate::params::Params;
|
||||||
use crate::utils::do_write_line;
|
use crate::utils::do_write_line;
|
||||||
|
use crate::utils::get_modification_time;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DiffLine {
|
pub enum DiffLine {
|
||||||
@@ -265,24 +266,7 @@ fn make_diff(
|
|||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_modification_time(file_path: &str) -> String {
|
|
||||||
use chrono::{DateTime, Local};
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
let metadata = fs::metadata(file_path).expect("Failed to get metadata");
|
|
||||||
let modification_time = metadata
|
|
||||||
.modified()
|
|
||||||
.expect("Failed to get modification time");
|
|
||||||
let modification_time: DateTime<Local> = modification_time.into();
|
|
||||||
let modification_time: String = modification_time
|
|
||||||
.format("%Y-%m-%d %H:%M:%S%.9f %z")
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
modification_time
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> {
|
pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> {
|
||||||
let from_modified_time = get_modification_time(¶ms.from.to_string_lossy());
|
let from_modified_time = get_modification_time(¶ms.from.to_string_lossy());
|
||||||
let to_modified_time = get_modification_time(¶ms.to.to_string_lossy());
|
let to_modified_time = get_modification_time(¶ms.to.to_string_lossy());
|
||||||
@@ -747,7 +731,6 @@ mod tests {
|
|||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
let target = "target/context-diff";
|
let target = "target/context-diff";
|
||||||
// test all possible six-line files.
|
|
||||||
let _ = std::fs::create_dir(target);
|
let _ = std::fs::create_dir(target);
|
||||||
let from_filename = &format!("{target}/foo");
|
let from_filename = &format!("{target}/foo");
|
||||||
let _ = File::create(from_filename).unwrap();
|
let _ = File::create(from_filename).unwrap();
|
||||||
|
|||||||
+51
-19
@@ -8,6 +8,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
use crate::params::Params;
|
use crate::params::Params;
|
||||||
use crate::utils::do_write_line;
|
use crate::utils::do_write_line;
|
||||||
|
use crate::utils::get_modification_time;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DiffLine {
|
pub enum DiffLine {
|
||||||
@@ -238,10 +239,14 @@ fn make_diff(
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> {
|
pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> {
|
||||||
|
let from_modified_time = get_modification_time(¶ms.from.to_string_lossy());
|
||||||
|
let to_modified_time = get_modification_time(¶ms.to.to_string_lossy());
|
||||||
let mut output = format!(
|
let mut output = format!(
|
||||||
"--- {0}\t\n+++ {1}\t\n",
|
"--- {0}\t{1}\n+++ {2}\t{3}\n",
|
||||||
params.from.to_string_lossy(),
|
params.from.to_string_lossy(),
|
||||||
params.to.to_string_lossy()
|
from_modified_time,
|
||||||
|
params.to.to_string_lossy(),
|
||||||
|
to_modified_time
|
||||||
)
|
)
|
||||||
.into_bytes();
|
.into_bytes();
|
||||||
let diff_results = make_diff(expected, actual, params.context_count, params.brief);
|
let diff_results = make_diff(expected, actual, params.context_count, params.brief);
|
||||||
@@ -449,13 +454,15 @@ mod tests {
|
|||||||
if f != 2 {
|
if f != 2 {
|
||||||
bet.write_all(b"l\n").unwrap();
|
bet.write_all(b"l\n").unwrap();
|
||||||
}
|
}
|
||||||
|
let _ = File::create(&format!("{target}/aalef")).unwrap();
|
||||||
|
let mut fa = File::create(&format!("{target}/alef")).unwrap();
|
||||||
// This test diff is intentionally reversed.
|
// This test diff is intentionally reversed.
|
||||||
// We want it to turn the alef into bet.
|
// We want it to turn the alef into bet.
|
||||||
let diff = diff(
|
let diff = diff(
|
||||||
&alef,
|
&alef,
|
||||||
&bet,
|
&bet,
|
||||||
&Params {
|
&Params {
|
||||||
from: "a/alef".into(),
|
from: (&format!("{target}/aalef")).into(),
|
||||||
to: (&format!("{target}/alef")).into(),
|
to: (&format!("{target}/alef")).into(),
|
||||||
context_count: 2,
|
context_count: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -465,7 +472,6 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.write_all(&diff)
|
.write_all(&diff)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut fa = File::create(&format!("{target}/alef")).unwrap();
|
|
||||||
fa.write_all(&alef[..]).unwrap();
|
fa.write_all(&alef[..]).unwrap();
|
||||||
let mut fb = File::create(&format!("{target}/bet")).unwrap();
|
let mut fb = File::create(&format!("{target}/bet")).unwrap();
|
||||||
fb.write_all(&bet[..]).unwrap();
|
fb.write_all(&bet[..]).unwrap();
|
||||||
@@ -565,13 +571,15 @@ mod tests {
|
|||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
let _ = File::create(&format!("{target}/aalefn")).unwrap();
|
||||||
|
let mut fa = File::create(&format!("{target}/alefn")).unwrap();
|
||||||
// This test diff is intentionally reversed.
|
// This test diff is intentionally reversed.
|
||||||
// We want it to turn the alef into bet.
|
// We want it to turn the alef into bet.
|
||||||
let diff = diff(
|
let diff = diff(
|
||||||
&alef,
|
&alef,
|
||||||
&bet,
|
&bet,
|
||||||
&Params {
|
&Params {
|
||||||
from: "a/alefn".into(),
|
from: (&format!("{target}/aalefn")).into(),
|
||||||
to: (&format!("{target}/alefn")).into(),
|
to: (&format!("{target}/alefn")).into(),
|
||||||
context_count: 2,
|
context_count: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -581,7 +589,6 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.write_all(&diff)
|
.write_all(&diff)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut fa = File::create(&format!("{target}/alefn")).unwrap();
|
|
||||||
fa.write_all(&alef[..]).unwrap();
|
fa.write_all(&alef[..]).unwrap();
|
||||||
let mut fb = File::create(&format!("{target}/betn")).unwrap();
|
let mut fb = File::create(&format!("{target}/betn")).unwrap();
|
||||||
fb.write_all(&bet[..]).unwrap();
|
fb.write_all(&bet[..]).unwrap();
|
||||||
@@ -661,13 +668,15 @@ mod tests {
|
|||||||
3 => {}
|
3 => {}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
let _ = File::create(&format!("{target}/aalef_")).unwrap();
|
||||||
|
let mut fa = File::create(&format!("{target}/alef_")).unwrap();
|
||||||
// This test diff is intentionally reversed.
|
// This test diff is intentionally reversed.
|
||||||
// We want it to turn the alef into bet.
|
// We want it to turn the alef into bet.
|
||||||
let diff = diff(
|
let diff = diff(
|
||||||
&alef,
|
&alef,
|
||||||
&bet,
|
&bet,
|
||||||
&Params {
|
&Params {
|
||||||
from: "a/alef_".into(),
|
from: (&format!("{target}/aalef_")).into(),
|
||||||
to: (&format!("{target}/alef_")).into(),
|
to: (&format!("{target}/alef_")).into(),
|
||||||
context_count: 2,
|
context_count: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -677,7 +686,6 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.write_all(&diff)
|
.write_all(&diff)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut fa = File::create(&format!("{target}/alef_")).unwrap();
|
|
||||||
fa.write_all(&alef[..]).unwrap();
|
fa.write_all(&alef[..]).unwrap();
|
||||||
let mut fb = File::create(&format!("{target}/bet_")).unwrap();
|
let mut fb = File::create(&format!("{target}/bet_")).unwrap();
|
||||||
fb.write_all(&bet[..]).unwrap();
|
fb.write_all(&bet[..]).unwrap();
|
||||||
@@ -742,13 +750,15 @@ mod tests {
|
|||||||
if f != 2 {
|
if f != 2 {
|
||||||
bet.write_all(b"l\n").unwrap();
|
bet.write_all(b"l\n").unwrap();
|
||||||
}
|
}
|
||||||
|
let _ = File::create(&format!("{target}/aalefx")).unwrap();
|
||||||
|
let mut fa = File::create(&format!("{target}/alefx")).unwrap();
|
||||||
// This test diff is intentionally reversed.
|
// This test diff is intentionally reversed.
|
||||||
// We want it to turn the alef into bet.
|
// We want it to turn the alef into bet.
|
||||||
let diff = diff(
|
let diff = diff(
|
||||||
&alef,
|
&alef,
|
||||||
&bet,
|
&bet,
|
||||||
&Params {
|
&Params {
|
||||||
from: "a/alefx".into(),
|
from: (&format!("{target}/aalefx")).into(),
|
||||||
to: (&format!("{target}/alefx")).into(),
|
to: (&format!("{target}/alefx")).into(),
|
||||||
context_count: 2,
|
context_count: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -758,7 +768,6 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.write_all(&diff)
|
.write_all(&diff)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut fa = File::create(&format!("{target}/alefx")).unwrap();
|
|
||||||
fa.write_all(&alef[..]).unwrap();
|
fa.write_all(&alef[..]).unwrap();
|
||||||
let mut fb = File::create(&format!("{target}/betx")).unwrap();
|
let mut fb = File::create(&format!("{target}/betx")).unwrap();
|
||||||
fb.write_all(&bet[..]).unwrap();
|
fb.write_all(&bet[..]).unwrap();
|
||||||
@@ -828,13 +837,15 @@ mod tests {
|
|||||||
if f != 2 {
|
if f != 2 {
|
||||||
bet.write_all(b"f\n").unwrap();
|
bet.write_all(b"f\n").unwrap();
|
||||||
}
|
}
|
||||||
|
let _ = File::create(&format!("{target}/aalefr")).unwrap();
|
||||||
|
let mut fa = File::create(&format!("{target}/alefr")).unwrap();
|
||||||
// This test diff is intentionally reversed.
|
// This test diff is intentionally reversed.
|
||||||
// We want it to turn the alef into bet.
|
// We want it to turn the alef into bet.
|
||||||
let diff = diff(
|
let diff = diff(
|
||||||
&alef,
|
&alef,
|
||||||
&bet,
|
&bet,
|
||||||
&Params {
|
&Params {
|
||||||
from: "a/alefr".into(),
|
from: (&format!("{target}/aalefr")).into(),
|
||||||
to: (&format!("{target}/alefr")).into(),
|
to: (&format!("{target}/alefr")).into(),
|
||||||
context_count: 2,
|
context_count: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -844,7 +855,6 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.write_all(&diff)
|
.write_all(&diff)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut fa = File::create(&format!("{target}/alefr")).unwrap();
|
|
||||||
fa.write_all(&alef[..]).unwrap();
|
fa.write_all(&alef[..]).unwrap();
|
||||||
let mut fb = File::create(&format!("{target}/betr")).unwrap();
|
let mut fb = File::create(&format!("{target}/betr")).unwrap();
|
||||||
fb.write_all(&bet[..]).unwrap();
|
fb.write_all(&bet[..]).unwrap();
|
||||||
@@ -870,9 +880,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stop_early() {
|
fn test_stop_early() {
|
||||||
let from_filename = "foo";
|
use regex::Regex;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
let target = "target/context-diff";
|
||||||
|
let _ = std::fs::create_dir(target);
|
||||||
|
let from_filename = &format!("{target}/foo");
|
||||||
|
let _ = File::create(from_filename).unwrap();
|
||||||
let from = ["a", "b", "c", ""].join("\n");
|
let from = ["a", "b", "c", ""].join("\n");
|
||||||
let to_filename = "bar";
|
let to_filename = &format!("{target}/bar");
|
||||||
|
let _ = File::create(to_filename).unwrap();
|
||||||
let to = ["a", "d", "c", ""].join("\n");
|
let to = ["a", "d", "c", ""].join("\n");
|
||||||
|
|
||||||
let diff_full = diff(
|
let diff_full = diff(
|
||||||
@@ -884,9 +902,14 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let diff_full_text = str::from_utf8(&diff_full).unwrap();
|
||||||
|
let re = Regex::new(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+ [+-]\d{4}").unwrap();
|
||||||
|
let diff_full = re.replace_all(diff_full_text, "");
|
||||||
|
|
||||||
let expected_full = [
|
let expected_full = [
|
||||||
"--- foo\t",
|
"--- target/context-diff/foo\t",
|
||||||
"+++ bar\t",
|
"+++ target/context-diff/bar\t",
|
||||||
"@@ -1,3 +1,3 @@",
|
"@@ -1,3 +1,3 @@",
|
||||||
" a",
|
" a",
|
||||||
"-b",
|
"-b",
|
||||||
@@ -895,7 +918,7 @@ mod tests {
|
|||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
.join("\n");
|
.join("\n");
|
||||||
assert_eq!(diff_full, expected_full.as_bytes());
|
assert_eq!(diff_full, expected_full);
|
||||||
|
|
||||||
let diff_brief = diff(
|
let diff_brief = diff(
|
||||||
from.as_bytes(),
|
from.as_bytes(),
|
||||||
@@ -907,8 +930,17 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let expected_brief = ["--- foo\t", "+++ bar\t", ""].join("\n");
|
|
||||||
assert_eq!(diff_brief, expected_brief.as_bytes());
|
let diff_brief_text = str::from_utf8(&diff_brief).unwrap();
|
||||||
|
let re = Regex::new(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+ [+-]\d{4}").unwrap();
|
||||||
|
let diff_brief = re.replace_all(diff_brief_text, "");
|
||||||
|
let expected_brief = [
|
||||||
|
"--- target/context-diff/foo\t",
|
||||||
|
"+++ target/context-diff/bar\t",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
.join("\n");
|
||||||
|
assert_eq!(diff_brief, expected_brief);
|
||||||
|
|
||||||
let nodiff_full = diff(
|
let nodiff_full = diff(
|
||||||
from.as_bytes(),
|
from.as_bytes(),
|
||||||
|
|||||||
@@ -51,6 +51,22 @@ pub fn do_write_line(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_modification_time(file_path: &str) -> String {
|
||||||
|
use chrono::{DateTime, Local};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
let metadata = fs::metadata(file_path).expect("Failed to get metadata");
|
||||||
|
let modification_time = metadata
|
||||||
|
.modified()
|
||||||
|
.expect("Failed to get modification time");
|
||||||
|
let modification_time: DateTime<Local> = modification_time.into();
|
||||||
|
let modification_time: String = modification_time
|
||||||
|
.format("%Y-%m-%d %H:%M:%S%.9f %z")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
modification_time
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user