mirror of
https://github.com/uutils/diffutils.git
synced 2026-05-06 14:17:17 -04:00
1ef6923b7d
Create the diff -y utility, this time introducing tests and changes focused
mainly on the construction of the utility and issues related to alignment
and response tabulation. New parameters were introduced such as the size
of the total width of the output in the parameters. A new calculation was
introduced to determine the size of the output columns and the maximum
total column size. The tab and spacing mechanism has the same behavior
as the original diff, with tabs and spaces formatted in the same way.
- Introducing tests for the diff 'main' function
- Introducing fuzzing for side diff utility
- Introducing tests for internal mechanisms
- Modular functions that allow consistent changes across the entire project
103 lines
3.4 KiB
Rust
103 lines
3.4 KiB
Rust
// This file is part of the uutils diffutils package.
|
|
//
|
|
// For the full copyright and license information, please view the LICENSE-*
|
|
// files that was distributed with this source code.
|
|
|
|
use crate::params::{parse_params, Format};
|
|
use crate::utils::report_failure_to_read_input_file;
|
|
use crate::{context_diff, ed_diff, normal_diff, side_diff, unified_diff};
|
|
use std::env::ArgsOs;
|
|
use std::ffi::OsString;
|
|
use std::fs;
|
|
use std::io::{self, stdout, Read, Write};
|
|
use std::iter::Peekable;
|
|
use std::process::{exit, ExitCode};
|
|
|
|
// Exit codes are documented at
|
|
// https://www.gnu.org/software/diffutils/manual/html_node/Invoking-diff.html.
|
|
// An exit status of 0 means no differences were found,
|
|
// 1 means some differences were found,
|
|
// and 2 means trouble.
|
|
pub fn main(opts: Peekable<ArgsOs>) -> ExitCode {
|
|
let params = parse_params(opts).unwrap_or_else(|error| {
|
|
eprintln!("{error}");
|
|
exit(2);
|
|
});
|
|
// if from and to are the same file, no need to perform any comparison
|
|
let maybe_report_identical_files = || {
|
|
if params.report_identical_files {
|
|
println!(
|
|
"Files {} and {} are identical",
|
|
params.from.to_string_lossy(),
|
|
params.to.to_string_lossy(),
|
|
);
|
|
}
|
|
};
|
|
if params.from == "-" && params.to == "-"
|
|
|| same_file::is_same_file(¶ms.from, ¶ms.to).unwrap_or(false)
|
|
{
|
|
maybe_report_identical_files();
|
|
return ExitCode::SUCCESS;
|
|
}
|
|
|
|
// read files
|
|
fn read_file_contents(filepath: &OsString) -> io::Result<Vec<u8>> {
|
|
if filepath == "-" {
|
|
let mut content = Vec::new();
|
|
io::stdin().read_to_end(&mut content).and(Ok(content))
|
|
} else {
|
|
fs::read(filepath)
|
|
}
|
|
}
|
|
let mut io_error = false;
|
|
let from_content = match read_file_contents(¶ms.from) {
|
|
Ok(from_content) => from_content,
|
|
Err(e) => {
|
|
report_failure_to_read_input_file(¶ms.executable, ¶ms.from, &e);
|
|
io_error = true;
|
|
vec![]
|
|
}
|
|
};
|
|
let to_content = match read_file_contents(¶ms.to) {
|
|
Ok(to_content) => to_content,
|
|
Err(e) => {
|
|
report_failure_to_read_input_file(¶ms.executable, ¶ms.to, &e);
|
|
io_error = true;
|
|
vec![]
|
|
}
|
|
};
|
|
if io_error {
|
|
return ExitCode::from(2);
|
|
}
|
|
|
|
// run diff
|
|
let result: Vec<u8> = match params.format {
|
|
Format::Normal => normal_diff::diff(&from_content, &to_content, ¶ms),
|
|
Format::Unified => unified_diff::diff(&from_content, &to_content, ¶ms),
|
|
Format::Context => context_diff::diff(&from_content, &to_content, ¶ms),
|
|
Format::Ed => ed_diff::diff(&from_content, &to_content, ¶ms).unwrap_or_else(|error| {
|
|
eprintln!("{error}");
|
|
exit(2);
|
|
}),
|
|
Format::SideBySide => {
|
|
let mut output = stdout().lock();
|
|
side_diff::diff(&from_content, &to_content, &mut output, ¶ms)
|
|
}
|
|
};
|
|
if params.brief && !result.is_empty() {
|
|
println!(
|
|
"Files {} and {} differ",
|
|
params.from.to_string_lossy(),
|
|
params.to.to_string_lossy()
|
|
);
|
|
} else {
|
|
io::stdout().write_all(&result).unwrap();
|
|
}
|
|
if result.is_empty() {
|
|
maybe_report_identical_files();
|
|
ExitCode::SUCCESS
|
|
} else {
|
|
ExitCode::from(1)
|
|
}
|
|
}
|