diff_edit: improve error handling

Used to produce a message like this:

```
thread 'main' panicked at 'failed to run diff editor: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/diff_edit.rs:136:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

Now produces a message like this:

```
Error: Failed to edit diff: Error executing editor 'meld': No such file or directory (os error 2)
```
This commit is contained in:
Waleed Khan 2022-04-30 12:43:02 -07:00 committed by Martin von Zweigbergk
parent 2b843d418b
commit 00a8abcdbb

View file

@ -30,12 +30,22 @@ use jujutsu_lib::working_copy::{CheckoutError, TreeState};
use tempfile::tempdir;
use thiserror::Error;
#[derive(Debug, Error, PartialEq, Eq)]
#[derive(Debug, Error)]
pub enum DiffEditError {
#[error("The diff tool exited with a non-zero code")]
DifftoolAborted,
#[error("Failed to write directories to diff: {0:?}")]
CheckoutError(CheckoutError),
#[error("Error setting up temporary directory: {0:?}")]
SetUpDirError(#[source] std::io::Error),
#[error("Error executing editor '{editor_binary}': {source}")]
ExecuteEditorError {
editor_binary: String,
#[source]
source: std::io::Error,
},
#[error("I/O error: {0:?}")]
IoError(#[source] std::io::Error),
#[error("Internal error: {0:?}")]
InternalBackendError(BackendError),
}
@ -59,23 +69,23 @@ fn check_out(
tree: &Tree,
sparse_patterns: Vec<RepoPath>,
) -> Result<TreeState, DiffEditError> {
std::fs::create_dir(&wc_dir).unwrap();
std::fs::create_dir(&state_dir).unwrap();
std::fs::create_dir(&wc_dir).map_err(DiffEditError::SetUpDirError)?;
std::fs::create_dir(&state_dir).map_err(DiffEditError::SetUpDirError)?;
let mut tree_state = TreeState::init(store, wc_dir, state_dir);
tree_state.set_sparse_patterns(sparse_patterns)?;
tree_state.check_out(tree)?;
Ok(tree_state)
}
fn set_readonly_recursively(path: &Path) {
fn set_readonly_recursively(path: &Path) -> Result<(), std::io::Error> {
if path.is_dir() {
for entry in path.read_dir().unwrap() {
set_readonly_recursively(&entry.unwrap().path());
for entry in path.read_dir()? {
set_readonly_recursively(&entry?.path())?;
}
}
let mut perms = std::fs::metadata(path).unwrap().permissions();
let mut perms = std::fs::metadata(path)?.permissions();
perms.set_readonly(true);
std::fs::set_permissions(path, perms).unwrap();
std::fs::set_permissions(path, perms)
}
pub fn edit_diff(
@ -93,7 +103,7 @@ pub fn edit_diff(
// Check out the two trees in temporary directories. Only include changed files
// in the sparse checkout patterns.
let temp_dir = tempdir().unwrap();
let temp_dir = tempdir().map_err(DiffEditError::SetUpDirError)?;
let left_wc_dir = temp_dir.path().join("left");
let left_state_dir = temp_dir.path().join("left_state");
let right_wc_dir = temp_dir.path().join("right");
@ -105,7 +115,7 @@ pub fn edit_diff(
left_tree,
changed_files.clone(),
)?;
set_readonly_recursively(&left_wc_dir);
set_readonly_recursively(&left_wc_dir).map_err(DiffEditError::SetUpDirError)?;
let mut right_tree_state = check_out(
store.clone(),
right_wc_dir.clone(),
@ -118,8 +128,9 @@ pub fn edit_diff(
// not get any instructions.
let add_instructions = !instructions.is_empty() && !instructions_path.exists();
if add_instructions {
let mut file = File::create(&instructions_path).unwrap();
file.write_all(instructions.as_bytes()).unwrap();
let mut file = File::create(&instructions_path).map_err(DiffEditError::SetUpDirError)?;
file.write_all(instructions.as_bytes())
.map_err(DiffEditError::SetUpDirError)?;
}
// TODO: Make this configuration have a table of possible editors and detect the
@ -133,7 +144,10 @@ pub fn edit_diff(
.arg(&left_wc_dir)
.arg(&right_wc_dir)
.status()
.expect("failed to run diff editor");
.map_err(|e| DiffEditError::ExecuteEditorError {
editor_binary,
source: e,
})?;
if !exit_status.success() {
return Err(DiffEditError::DifftoolAborted);
}