Convert more ShellError variants to named fields (#11173)

# Description

Convert these ShellError variants to named fields:
* CreateNotPossible
* MoveNotPossibleSingle
* DirectoryNotFoundCustom
* DirectoryNotFound
* NotADirectory
* OutOfMemoryError
* PermissionDeniedError
* IOErrorSpanned
* IOError
* IOInterrupted

Also place the `span` field of `DirectoryNotFound` last to match other
errors.

Part of #10700 (almost half done!)

# User-Facing Changes

None

# Tests + Formatting

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting

N/A
This commit is contained in:
Eric Hodel
2023-11-28 04:43:51 -08:00
committed by GitHub
parent 182b0ab4fb
commit 8386bc0919
21 changed files with 241 additions and 116 deletions

View File

@ -83,10 +83,10 @@ impl Command for Cd {
let path = match nu_path::canonicalize_with(path.clone(), &cwd) {
Ok(p) => p,
Err(_) => {
return Err(ShellError::DirectoryNotFound(
v.span,
path.to_string_lossy().to_string(),
));
return Err(ShellError::DirectoryNotFound {
dir: path.to_string_lossy().to_string(),
span: v.span,
});
}
};
(path.to_string_lossy().to_string(), v.span)
@ -100,17 +100,17 @@ impl Command for Cd {
let path = match nu_path::canonicalize_with(path_no_whitespace, &cwd) {
Ok(p) => {
if !p.is_dir() {
return Err(ShellError::NotADirectory(v.span));
return Err(ShellError::NotADirectory { span: v.span });
};
p
}
// if canonicalize failed, let's check to see if it's abbreviated
Err(_) => {
return Err(ShellError::DirectoryNotFound(
v.span,
path_no_whitespace.to_string(),
));
return Err(ShellError::DirectoryNotFound {
dir: path_no_whitespace.to_string(),
span: v.span,
});
}
};
(path.to_string_lossy().to_string(), v.span)
@ -135,9 +135,9 @@ impl Command for Cd {
stack.add_env_var("PWD".into(), path_value);
Ok(PipelineData::empty())
}
PermissionResult::PermissionDenied(reason) => Err(ShellError::IOError(format!(
"Cannot change directory to {path}: {reason}"
))),
PermissionResult::PermissionDenied(reason) => Err(ShellError::IOError {
msg: format!("Cannot change directory to {path}: {reason}"),
}),
}
}

View File

@ -88,10 +88,10 @@ impl Command for Cp {
let path_last_char = destination.as_os_str().to_string_lossy().chars().last();
let is_directory = path_last_char == Some('/') || path_last_char == Some('\\');
if is_directory && !destination.exists() {
return Err(ShellError::DirectoryNotFound(
dst.span,
destination.to_string_lossy().to_string(),
));
return Err(ShellError::DirectoryNotFound {
dir: destination.to_string_lossy().to_string(),
span: dst.span,
});
}
let ctrlc = engine_state.ctrlc.clone();
let span = call.head;
@ -577,18 +577,36 @@ fn convert_io_error(error: std::io::Error, src: PathBuf, dst: PathBuf, span: Spa
ErrorKind::PermissionDenied => match std::fs::metadata(&dst) {
Ok(meta) => {
if meta.permissions().readonly() {
ShellError::PermissionDeniedError(message_dst, span)
ShellError::PermissionDeniedError {
msg: message_dst,
span,
}
} else {
ShellError::PermissionDeniedError(message_src, span)
ShellError::PermissionDeniedError {
msg: message_src,
span,
}
}
}
Err(_) => ShellError::PermissionDeniedError(message_dst, span),
Err(_) => ShellError::PermissionDeniedError {
msg: message_dst,
span,
},
},
ErrorKind::Interrupted => ShellError::IOInterrupted {
msg: message_src,
span,
},
ErrorKind::OutOfMemory => ShellError::OutOfMemoryError {
msg: message_src,
span,
},
ErrorKind::Interrupted => ShellError::IOInterrupted(message_src, span),
ErrorKind::OutOfMemory => ShellError::OutOfMemoryError(message_src, span),
// TODO: handle ExecutableFileBusy etc. when io_error_more is stabilized
// https://github.com/rust-lang/rust/issues/86442
_ => ShellError::IOErrorSpanned(message_src, span),
_ => ShellError::IOErrorSpanned {
msg: message_src,
span,
},
};
Value::error(shell_error, span)

View File

@ -69,12 +69,13 @@ impl Command for Mkdir {
let dir_res = std::fs::create_dir_all(&dir);
if let Err(reason) = dir_res {
return Err(ShellError::CreateNotPossible(
format!("failed to create directory: {reason}"),
call.positional_nth(i)
return Err(ShellError::CreateNotPossible {
msg: format!("failed to create directory: {reason}"),
span: call
.positional_nth(i)
.expect("already checked through directories")
.span,
));
});
}
if is_verbose {

View File

@ -110,10 +110,14 @@ impl Command for Mktemp {
};
let res = match uu_mktemp::mktemp(&options) {
Ok(res) => res
.into_os_string()
.into_string()
.map_err(|e| ShellError::IOErrorSpanned(e.to_string_lossy().to_string(), span))?,
Ok(res) => {
res.into_os_string()
.into_string()
.map_err(|e| ShellError::IOErrorSpanned {
msg: e.to_string_lossy().to_string(),
span,
})?
}
Err(e) => {
return Err(ShellError::GenericError(
format!("{}", e),

View File

@ -260,10 +260,10 @@ fn move_file(
};
if !destination_dir_exists {
return Err(ShellError::DirectoryNotFound(
to_span,
to.to_string_lossy().to_string(),
));
return Err(ShellError::DirectoryNotFound {
dir: to.to_string_lossy().to_string(),
span: to_span,
});
}
// This can happen when changing case on a case-insensitive filesystem (ex: changing foo to Foo on Windows)
@ -275,10 +275,10 @@ fn move_file(
let from_file_name = match from.file_name() {
Some(name) => name,
None => {
return Err(ShellError::DirectoryNotFound(
to_span,
from.to_string_lossy().to_string(),
))
return Err(ShellError::DirectoryNotFound {
dir: from.to_string_lossy().to_string(),
span: to_span,
})
}
};

View File

@ -105,7 +105,7 @@ impl Command for Open {
for path in nu_engine::glob_from(&path, &cwd, call_span, None)
.map_err(|err| match err {
ShellError::DirectoryNotFound(span, _) => ShellError::FileNotFound { span },
ShellError::DirectoryNotFound { span, .. } => ShellError::FileNotFound { span },
_ => err,
})?
.1

View File

@ -162,9 +162,13 @@ impl Command for Save {
)?;
for val in ls {
file.write_all(&value_to_bytes(val)?)
.map_err(|err| ShellError::IOError(err.to_string()))?;
.map_err(|err| ShellError::IOError {
msg: err.to_string(),
})?;
file.write_all("\n".as_bytes())
.map_err(|err| ShellError::IOError(err.to_string()))?;
.map_err(|err| ShellError::IOError {
msg: err.to_string(),
})?;
}
file.flush()?;
@ -184,8 +188,9 @@ impl Command for Save {
force,
)?;
file.write_all(&bytes)
.map_err(|err| ShellError::IOError(err.to_string()))?;
file.write_all(&bytes).map_err(|err| ShellError::IOError {
msg: err.to_string(),
})?;
file.flush()?;
@ -453,7 +458,9 @@ fn stream_to_file(
if let Err(err) = writer.write(&buf) {
*process_failed_p = true;
return Err(ShellError::IOError(err.to_string()));
return Err(ShellError::IOError {
msg: err.to_string(),
});
}
Ok(())
})

View File

@ -136,12 +136,13 @@ impl Command for Touch {
}
if let Err(err) = OpenOptions::new().write(true).create(true).open(&item) {
return Err(ShellError::CreateNotPossible(
format!("Failed to create file: {err}"),
call.positional_nth(index)
return Err(ShellError::CreateNotPossible {
msg: format!("Failed to create file: {err}"),
span: call
.positional_nth(index)
.expect("already checked positional")
.span,
));
});
};
if change_mtime {

View File

@ -83,10 +83,10 @@ impl Command for Watch {
let path = match nu_path::canonicalize_with(path_no_whitespace, cwd) {
Ok(p) => p,
Err(_) => {
return Err(ShellError::DirectoryNotFound(
path_arg.span,
path_no_whitespace.to_string(),
))
return Err(ShellError::DirectoryNotFound {
dir: path_no_whitespace.to_string(),
span: path_arg.span,
})
}
};
@ -153,15 +153,15 @@ impl Command for Watch {
let mut debouncer = match new_debouncer(debounce_duration, None, tx) {
Ok(d) => d,
Err(e) => {
return Err(ShellError::IOError(format!(
"Failed to create watcher: {e}"
)))
return Err(ShellError::IOError {
msg: format!("Failed to create watcher: {e}"),
})
}
};
if let Err(e) = debouncer.watcher().watch(&path, recursive_mode) {
return Err(ShellError::IOError(format!(
"Failed to create watcher: {e}"
)));
return Err(ShellError::IOError {
msg: format!("Failed to create watcher: {e}"),
});
}
// need to cache to make sure that rename event works.
debouncer.cache().add_root(&path, recursive_mode);
@ -275,14 +275,14 @@ impl Command for Watch {
}
}
Ok(Err(_)) => {
return Err(ShellError::IOError(
"Unexpected errors when receiving events".into(),
))
return Err(ShellError::IOError {
msg: "Unexpected errors when receiving events".into(),
})
}
Err(RecvTimeoutError::Disconnected) => {
return Err(ShellError::IOError(
"Unexpected disconnect from file watcher".into(),
));
return Err(ShellError::IOError {
msg: "Unexpected disconnect from file watcher".into(),
});
}
Err(RecvTimeoutError::Timeout) => {}
}

View File

@ -209,9 +209,9 @@ pub fn send_request(
}
Value::List { vals, .. } if body_type == BodyType::Form => {
if vals.len() % 2 != 0 {
return Err(ShellErrorOrRequestError::ShellError(ShellError::IOError(
"unsupported body input".into(),
)));
return Err(ShellErrorOrRequestError::ShellError(ShellError::IOError {
msg: "unsupported body input".into(),
}));
}
let data = vals
@ -233,9 +233,9 @@ pub fn send_request(
let data = value_to_json_value(&body)?;
send_cancellable_request(&request_url, Box::new(|| request.send_json(data)), ctrl_c)
}
_ => Err(ShellErrorOrRequestError::ShellError(ShellError::IOError(
"unsupported body input".into(),
))),
_ => Err(ShellErrorOrRequestError::ShellError(ShellError::IOError {
msg: "unsupported body input".into(),
})),
}
}

View File

@ -135,7 +135,13 @@ fn exists(path: &Path, span: Span, args: &Arguments) -> Value {
match path.try_exists() {
Ok(exists) => exists,
Err(err) => {
return Value::error(ShellError::IOErrorSpanned(err.to_string(), span), span)
return Value::error(
ShellError::IOErrorSpanned {
msg: err.to_string(),
span,
},
span,
)
}
},
span,

View File

@ -36,7 +36,10 @@ impl Command for Clear {
CommandSys::new("cmd")
.args(["/C", "cls"])
.status()
.map_err(|e| ShellError::IOErrorSpanned(e.to_string(), span))?;
.map_err(|e| ShellError::IOErrorSpanned {
msg: e.to_string(),
span,
})?;
} else if cfg!(unix) {
let mut cmd = CommandSys::new("/bin/sh");
@ -46,7 +49,10 @@ impl Command for Clear {
cmd.args(["-c", "clear"])
.status()
.map_err(|e| ShellError::IOErrorSpanned(e.to_string(), span))?;
.map_err(|e| ShellError::IOErrorSpanned {
msg: e.to_string(),
span,
})?;
}
Ok(Value::nothing(span).into_pipeline_data())

View File

@ -110,7 +110,9 @@ impl Command for Input {
{
if k.modifiers == KeyModifiers::CONTROL && c == 'c' {
crossterm::terminal::disable_raw_mode()?;
return Err(ShellError::IOError("SIGINT".to_string()));
return Err(ShellError::IOError {
msg: "SIGINT".to_string(),
});
}
continue;
}

View File

@ -196,7 +196,9 @@ impl Command for InputList {
.items(&options)
.report(false)
.interact_on_opt(&Term::stderr())
.map_err(|err| ShellError::IOError(format!("{}: {}", INTERACT_ERROR, err)))?,
.map_err(|err| ShellError::IOError {
msg: format!("{}: {}", INTERACT_ERROR, err),
})?,
)
} else if call.has_flag("fuzzy") {
let fuzzy_select = FuzzySelect::new(); //::with_theme(&theme);
@ -211,7 +213,9 @@ impl Command for InputList {
.default(0)
.report(false)
.interact_on_opt(&Term::stderr())
.map_err(|err| ShellError::IOError(format!("{}: {}", INTERACT_ERROR, err)))?,
.map_err(|err| ShellError::IOError {
msg: format!("{}: {}", INTERACT_ERROR, err),
})?,
)
} else {
let select = Select::new(); //::with_theme(&theme);
@ -225,7 +229,9 @@ impl Command for InputList {
.default(0)
.report(false)
.interact_on_opt(&Term::stderr())
.map_err(|err| ShellError::IOError(format!("{}: {}", INTERACT_ERROR, err)))?,
.map_err(|err| ShellError::IOError {
msg: format!("{}: {}", INTERACT_ERROR, err),
})?,
)
};

View File

@ -301,7 +301,9 @@ fn heuristic_parse_file(
}
}
} else {
Err(ShellError::IOError("Can not read input".to_string()))
Err(ShellError::IOError {
msg: "Can not read input".to_string(),
})
}
} else {
Err(ShellError::NotFound { span: call.head })
@ -402,7 +404,9 @@ fn parse_file_script(
call.head,
)
} else {
Err(ShellError::IOError("Can not read path".to_string()))
Err(ShellError::IOError {
msg: "Can not read path".to_string(),
})
}
} else {
Err(ShellError::NotFound { span: call.head })
@ -425,7 +429,9 @@ fn parse_file_module(
if let Ok(contents) = std::fs::read(path) {
parse_module(working_set, Some(filename), &contents, is_debug, call.head)
} else {
Err(ShellError::IOError("Can not read path".to_string()))
Err(ShellError::IOError {
msg: "Can not read path".to_string(),
})
}
} else {
Err(ShellError::NotFound { span: call.head })