Fix Mercurial when whole file has been removed

Mercurial gives us the path even when it doesn't exist. Just require
at least one of the paths to exist, rather than both.

(Git gives us /dev/null in this situation.)

Fixes #50
a_star_module
Wilfred Hughes 2022-01-07 09:42:56 +07:00
parent 71d357b92e
commit d240bfeebd
3 changed files with 54 additions and 18 deletions

@ -1,5 +1,9 @@
## 0.16 (unreleased)
### Integration
Fixed a crash when on Mercurial diffs when a whole file has been removed.
## 0.15 (released 6 January 2022)
### Parsing

@ -1,26 +1,58 @@
//! File reading utilities.
use std::{fs, path::Path};
use std::{fs, io::ErrorKind::*, path::Path};
pub fn read_files_or_die(lhs_path: &Path, rhs_path: &Path) -> (Vec<u8>, Vec<u8>) {
let lhs_res = fs::read(lhs_path);
let rhs_res = fs::read(rhs_path);
match (lhs_res, rhs_res) {
// Both files exist, the happy case.
(Ok(lhs_src), Ok(rhs_src)) => (lhs_src, rhs_src),
// Proceed if we've been given two paths and only one
// exists. This is important for mercurial diffs when a file
// has been removed.
//
// TODO: we're still computing a diff when one side is "", which is pointless.
(Ok(lhs_src), Err(e)) if e.kind() == NotFound => (lhs_src, vec![]),
(Err(e), Ok(rhs_src)) if e.kind() == NotFound => (vec![], rhs_src),
(lhs_res, rhs_res) => {
// Something else went wrong. Print both errors
// encountered.
if let Err(e) = lhs_res {
eprint_read_error(lhs_path, &e);
}
if let Err(e) = rhs_res {
eprint_read_error(rhs_path, &e);
}
std::process::exit(1);
}
}
}
fn eprint_read_error(path: &Path, e: &std::io::Error) {
match e.kind() {
std::io::ErrorKind::NotFound => {
eprintln!("No such file: {}", path.display());
}
std::io::ErrorKind::PermissionDenied => {
eprintln!("Permission denied when reading file: {}", path.display());
}
_ => {
eprintln!(
"Could not read file: {} (error {:?})",
path.display(),
e.kind()
);
}
};
}
pub fn read_or_die(path: &Path) -> Vec<u8> {
match fs::read(path) {
Ok(src) => src,
Err(e) => {
match e.kind() {
std::io::ErrorKind::NotFound => {
eprintln!("No such file: {}", path.display());
}
std::io::ErrorKind::PermissionDenied => {
eprintln!("Permission denied when reading file: {}", path.display());
}
_ => {
eprintln!(
"Could not read file: {} (error {:?})",
path.display(),
e.kind()
);
}
};
eprint_read_error(path, &e);
std::process::exit(1);
}
}

@ -24,6 +24,7 @@ mod tree_sitter_parser;
extern crate log;
use crate::hunks::{matched_pos_to_hunks, merge_adjacent};
use files::read_files_or_die;
use guess_language::guess;
use log::info;
use mimalloc::MiMalloc;
@ -241,8 +242,7 @@ fn main() {
/// Print a diff between two files.
fn diff_file(display_path: &str, lhs_path: &Path, rhs_path: &Path) -> DiffResult {
let lhs_bytes = read_or_die(lhs_path);
let rhs_bytes = read_or_die(rhs_path);
let (lhs_bytes, rhs_bytes) = read_files_or_die(lhs_path, rhs_path);
let lhs_binary = is_probably_binary(&lhs_bytes);
let rhs_binary = is_probably_binary(&rhs_bytes);