Refactor: Construct IoError from std::io::Error instead of std::io::ErrorKind (#15777)

This commit is contained in:
Piepmatz
2025-05-18 14:52:40 +02:00
committed by GitHub
parent c4dcfdb77b
commit 833471241a
80 changed files with 408 additions and 299 deletions

View File

@ -77,7 +77,7 @@ impl Command for BytesEndsWith {
Ok(&[]) => break,
Ok(buf) => buf,
Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => return Err(IoError::new(e.kind(), span, None).into()),
Err(e) => return Err(IoError::new(e, span, None).into()),
};
let len = buf.len();
if len >= cap {

View File

@ -72,7 +72,7 @@ impl Command for BytesStartsWith {
reader
.take(pattern.len() as u64)
.read_to_end(&mut start)
.map_err(|err| IoError::new(err.kind(), span, None))?;
.map_err(|err| IoError::new(err, span, None))?;
Ok(Value::bool(start == pattern, head).into_pipeline_data())
} else {

View File

@ -41,12 +41,11 @@ impl SQLiteDatabase {
}
pub fn try_from_path(path: &Path, span: Span, signals: Signals) -> Result<Self, ShellError> {
let mut file =
File::open(path).map_err(|e| IoError::new(e.kind(), span, PathBuf::from(path)))?;
let mut file = File::open(path).map_err(|e| IoError::new(e, span, PathBuf::from(path)))?;
let mut buf: [u8; 16] = [0; 16];
file.read_exact(&mut buf)
.map_err(|e| ShellError::Io(IoError::new(e.kind(), span, PathBuf::from(path))))
.map_err(|e| ShellError::Io(IoError::new(e, span, PathBuf::from(path))))
.and_then(|_| {
if buf == SQLITE_MAGIC_BYTES {
Ok(SQLiteDatabase::new(path, signals))

View File

@ -115,7 +115,7 @@ pub(super) fn start_editor(
let child = child.map_err(|err| {
IoError::new_with_additional_context(
err.kind(),
err,
call.head,
None,
"Could not spawn foreground child",

View File

@ -59,7 +59,7 @@ impl Command for ConfigReset {
));
if let Err(err) = std::fs::rename(nu_config.clone(), &backup_path) {
return Err(ShellError::Io(IoError::new_with_additional_context(
err.kind().not_found_as(NotFound::Directory),
err.not_found_as(NotFound::Directory),
span,
PathBuf::from(backup_path),
"config.nu could not be backed up",
@ -69,7 +69,7 @@ impl Command for ConfigReset {
if let Ok(mut file) = std::fs::File::create(&nu_config) {
if let Err(err) = writeln!(&mut file, "{config_file}") {
return Err(ShellError::Io(IoError::new_with_additional_context(
err.kind().not_found_as(NotFound::File),
err.not_found_as(NotFound::File),
span,
PathBuf::from(nu_config),
"config.nu could not be written to",
@ -86,7 +86,7 @@ impl Command for ConfigReset {
backup_path.push(format!("oldenv-{}.nu", Local::now().format("%F-%H-%M-%S"),));
if let Err(err) = std::fs::rename(env_config.clone(), &backup_path) {
return Err(ShellError::Io(IoError::new_with_additional_context(
err.kind().not_found_as(NotFound::Directory),
err.not_found_as(NotFound::Directory),
span,
PathBuf::from(backup_path),
"env.nu could not be backed up",
@ -96,7 +96,7 @@ impl Command for ConfigReset {
if let Ok(mut file) = std::fs::File::create(&env_config) {
if let Err(err) = writeln!(&mut file, "{config_file}") {
return Err(ShellError::Io(IoError::new_with_additional_context(
err.kind().not_found_as(NotFound::File),
err.not_found_as(NotFound::File),
span,
PathBuf::from(env_config),
"env.nu could not be written to",

View File

@ -2,7 +2,11 @@ use nu_engine::{
command_prelude::*, find_in_dirs_env, get_dirs_var_from_call, get_eval_block_with_early_return,
redirect_env,
};
use nu_protocol::{BlockId, engine::CommandType, shell_error::io::IoError};
use nu_protocol::{
BlockId,
engine::CommandType,
shell_error::{self, io::IoError},
};
use std::path::PathBuf;
/// Source a file for environment variables.
@ -66,7 +70,7 @@ impl Command for SourceEnv {
PathBuf::from(&path)
} else {
return Err(ShellError::Io(IoError::new(
std::io::ErrorKind::NotFound,
shell_error::io::ErrorKind::FileNotFound,
source_filename.span,
PathBuf::from(source_filename.item),
)));

View File

@ -53,7 +53,7 @@ impl Command for JobKill {
jobs.kill_and_remove(id).map_err(|err| {
ShellError::Io(IoError::new_internal(
err.kind(),
err,
"Failed to kill the requested job",
nu_protocol::location!(),
))

View File

@ -121,7 +121,7 @@ impl Command for JobSpawn {
Err(err) => {
jobs.remove_job(id);
Err(ShellError::Io(IoError::new_with_additional_context(
err.kind(),
err,
call.head,
None,
"Failed to spawn thread for job",

View File

@ -3,7 +3,6 @@ use nu_protocol::{
JobId,
engine::{FrozenJob, Job, ThreadJob},
process::check_ok,
shell_error,
};
use nu_system::{ForegroundWaitStatus, kill_by_pid};
@ -123,7 +122,7 @@ fn unfreeze_job(
if !thread_job.try_add_pid(pid) {
kill_by_pid(pid.into()).map_err(|err| {
ShellError::Io(IoError::new_internal(
err.kind(),
err,
"job was interrupted; could not kill foreground process",
nu_protocol::location!(),
))
@ -163,7 +162,7 @@ fn unfreeze_job(
Ok(ForegroundWaitStatus::Finished(status)) => check_ok(status, false, span),
Err(err) => Err(ShellError::Io(IoError::new_internal(
shell_error::io::ErrorKind::Std(err.kind()),
err,
"Failed to unfreeze foreground process",
nu_protocol::location!(),
))),

View File

@ -77,7 +77,7 @@ impl Command for Cd {
if let Ok(path) = nu_path::canonicalize_with(path_no_whitespace, &cwd) {
if !path.is_dir() {
return Err(shell_error::io::IoError::new(
shell_error::io::ErrorKind::Std(
shell_error::io::ErrorKind::from_std(
std::io::ErrorKind::NotADirectory,
),
v.span,
@ -106,7 +106,9 @@ impl Command for Cd {
};
if !path.is_dir() {
return Err(shell_error::io::IoError::new(
shell_error::io::ErrorKind::Std(std::io::ErrorKind::NotADirectory),
shell_error::io::ErrorKind::from_std(
std::io::ErrorKind::NotADirectory,
),
v.span,
path,
)
@ -132,9 +134,12 @@ impl Command for Cd {
stack.set_cwd(path)?;
Ok(PipelineData::empty())
}
PermissionResult::PermissionDenied => {
Err(IoError::new(std::io::ErrorKind::PermissionDenied, call.head, path).into())
}
PermissionResult::PermissionDenied => Err(IoError::new(
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::PermissionDenied),
call.head,
path,
)
.into()),
}
}

View File

@ -5,7 +5,10 @@ use nu_engine::glob_from;
use nu_engine::{command_prelude::*, env::current_dir};
use nu_glob::MatchOptions;
use nu_path::{expand_path_with, expand_to_real_path};
use nu_protocol::{DataSource, NuGlob, PipelineMetadata, Signals, shell_error::io::IoError};
use nu_protocol::{
DataSource, NuGlob, PipelineMetadata, Signals,
shell_error::{self, io::IoError},
};
use pathdiff::diff_paths;
use rayon::prelude::*;
#[cfg(unix)]
@ -252,7 +255,7 @@ fn ls_for_one_pattern(
// it makes no sense to list an empty string.
if path.item.as_ref().is_empty() {
return Err(ShellError::Io(IoError::new_with_additional_context(
std::io::ErrorKind::NotFound,
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::NotFound),
path.span,
PathBuf::from(path.item.to_string()),
"empty string('') directory or file does not exist",
@ -357,7 +360,7 @@ fn ls_for_one_pattern(
let count = std::thread::available_parallelism()
.map_err(|err| {
IoError::new_with_additional_context(
err.kind(),
err,
call_span,
None,
"Could not get available parallelism",
@ -793,6 +796,7 @@ fn unix_time_to_local_date_time(secs: i64) -> Option<DateTime<Local>> {
mod windows_helper {
use super::*;
use nu_protocol::shell_error;
use std::os::windows::prelude::OsStrExt;
use windows::Win32::Foundation::FILETIME;
use windows::Win32::Storage::FileSystem::{
@ -928,7 +932,7 @@ mod windows_helper {
Ok(find_data)
}
Err(e) => Err(ShellError::Io(IoError::new_with_additional_context(
std::io::ErrorKind::Other,
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::Other),
span,
PathBuf::from(filename),
format!("Could not read metadata: {e}"),
@ -973,11 +977,11 @@ fn read_dir(
let signals_clone = signals.clone();
let items = f
.read_dir()
.map_err(|err| IoError::new(err.kind(), span, f.clone()))?
.map_err(|err| IoError::new(err, span, f.clone()))?
.map(move |d| {
signals_clone.check(span)?;
d.map(|r| r.path())
.map_err(|err| IoError::new(err.kind(), span, f.clone()))
.map_err(|err| IoError::new(err, span, f.clone()))
.map_err(ShellError::from)
});
if !use_threads {

View File

@ -121,7 +121,7 @@ impl Command for Open {
if permission_denied(path) {
let err = IoError::new(
std::io::ErrorKind::PermissionDenied,
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::PermissionDenied),
arg_span,
PathBuf::from(path),
);
@ -162,14 +162,18 @@ impl Command for Open {
// At least under windows this check ensures that we don't get a
// permission denied error on directories
return Err(ShellError::Io(IoError::new(
shell_error::io::ErrorKind::Std(std::io::ErrorKind::IsADirectory),
#[allow(
deprecated,
reason = "we don't have a IsADirectory variant here, so we provide one"
)]
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::IsADirectory),
arg_span,
PathBuf::from(path),
)));
}
let file = std::fs::File::open(path)
.map_err(|err| IoError::new(err.kind(), arg_span, PathBuf::from(path)))?;
.map_err(|err| IoError::new(err, arg_span, PathBuf::from(path)))?;
// No content_type by default - Is added later if no converter is found
let stream = PipelineData::ByteStream(

View File

@ -304,7 +304,7 @@ fn rm(
&& matches!(
e,
ShellError::Io(IoError {
kind: shell_error::io::ErrorKind::Std(std::io::ErrorKind::NotFound),
kind: shell_error::io::ErrorKind::Std(std::io::ErrorKind::NotFound, ..),
..
})
))
@ -420,7 +420,7 @@ fn rm(
};
if let Err(e) = result {
Err(ShellError::Io(IoError::new(e.kind(), span, f)))
Err(ShellError::Io(IoError::new(e, span, f)))
} else if verbose {
let msg = if interactive && !confirmed {
"not deleted"

View File

@ -130,7 +130,7 @@ impl Command for Save {
io::copy(&mut tee, &mut io::stderr())
}
}
.map_err(|err| IoError::new(err.kind(), span, None))?;
.map_err(|err| IoError::new(err, span, None))?;
}
Ok(())
}
@ -428,20 +428,24 @@ fn open_file(path: &Path, span: Span, append: bool) -> Result<File, ShellError>
(true, true) => std::fs::OpenOptions::new()
.append(true)
.open(path)
.map_err(|err| err.kind().into()),
.map_err(|err| err.into()),
_ => {
// This is a temporary solution until `std::fs::File::create` is fixed on Windows (rust-lang/rust#134893)
// A TOCTOU problem exists here, which may cause wrong error message to be shown
#[cfg(target_os = "windows")]
if path.is_dir() {
Err(nu_protocol::shell_error::io::ErrorKind::Std(
#[allow(
deprecated,
reason = "we don't get a IsADirectory error, so we need to provide it"
)]
Err(nu_protocol::shell_error::io::ErrorKind::from_std(
std::io::ErrorKind::IsADirectory,
))
} else {
std::fs::File::create(path).map_err(|err| err.kind().into())
std::fs::File::create(path).map_err(|err| err.into())
}
#[cfg(not(target_os = "windows"))]
std::fs::File::create(path).map_err(|err| err.kind().into())
std::fs::File::create(path).map_err(|err| err.into())
}
};

View File

@ -1,6 +1,9 @@
#[allow(deprecated)]
use nu_engine::{command_prelude::*, current_dir};
use nu_protocol::{NuGlob, shell_error::io::IoError};
use nu_protocol::{
NuGlob,
shell_error::{self, io::IoError},
};
use std::path::PathBuf;
use uu_cp::{BackupMode, CopyMode, UpdateMode};
@ -198,7 +201,7 @@ impl Command for UCp {
.collect();
if exp_files.is_empty() {
return Err(ShellError::Io(IoError::new(
std::io::ErrorKind::NotFound,
shell_error::io::ErrorKind::FileNotFound,
p.span,
PathBuf::from(p.item.to_string()),
)));

View File

@ -1,7 +1,10 @@
#[allow(deprecated)]
use nu_engine::{command_prelude::*, current_dir};
use nu_path::expand_path_with;
use nu_protocol::{NuGlob, shell_error::io::IoError};
use nu_protocol::{
NuGlob,
shell_error::{self, io::IoError},
};
use std::{ffi::OsString, path::PathBuf};
use uu_mv::{BackupMode, UpdateMode};
@ -139,7 +142,7 @@ impl Command for UMv {
.collect();
if exp_files.is_empty() {
return Err(ShellError::Io(IoError::new(
std::io::ErrorKind::NotFound,
shell_error::io::ErrorKind::FileNotFound,
p.span,
PathBuf::from(p.item.to_string()),
)));

View File

@ -227,7 +227,7 @@ impl Command for UTouch {
TouchError::ReferenceFileInaccessible(reference_path, io_err) => {
let span = reference_span.expect("touch should've been given a reference file");
ShellError::Io(IoError::new_with_additional_context(
io_err.kind(),
io_err,
span,
reference_path,
"failed to read metadata",

View File

@ -86,7 +86,7 @@ impl Command for Watch {
Ok(p) => p,
Err(err) => {
return Err(ShellError::Io(IoError::new(
err.kind(),
err,
path_arg.span,
PathBuf::from(path_no_whitespace),
)));

View File

@ -37,7 +37,7 @@ pub fn empty(
.bytes()
.next()
.transpose()
.map_err(|err| IoError::new(err.kind(), span, None))?
.map_err(|err| IoError::new(err, span, None))?
.is_none();
if negate {
Ok(Value::bool(!is_empty, head).into_pipeline_data())

View File

@ -182,7 +182,7 @@ fn first_helper(
let mut byte = [0u8];
if reader
.read(&mut byte)
.map_err(|err| IoError::new(err.kind(), span, None))?
.map_err(|err| IoError::new(err, span, None))?
> 0
{
Ok(Value::int(byte[0] as i64, head).into_pipeline_data())

View File

@ -137,7 +137,7 @@ interleave
}
})
.map(|_| ())
.map_err(|err| IoError::new(err.kind(), head, None).into())
.map_err(|err| IoError::new(err, head, None).into())
})
})?;

View File

@ -166,7 +166,7 @@ impl Command for Last {
let mut buf = VecDeque::with_capacity(rows + TAKE as usize);
loop {
let taken = std::io::copy(&mut (&mut reader).take(TAKE), &mut buf)
.map_err(|err| IoError::new(err.kind(), span, None))?;
.map_err(|err| IoError::new(err, span, None))?;
if buf.len() > rows {
buf.drain(..(buf.len() - rows));
}

View File

@ -1,6 +1,8 @@
use nu_engine::{command_prelude::*, get_eval_block_with_early_return};
#[cfg(feature = "os")]
use nu_protocol::process::ChildPipe;
#[cfg(test)]
use nu_protocol::shell_error;
use nu_protocol::{
ByteStream, ByteStreamSource, OutDest, PipelineMetadata, Signals,
byte_stream::copy_with_signals, engine::Closure, report_shell_error, shell_error::io::IoError,
@ -440,7 +442,7 @@ fn spawn_tee(
eval_block(PipelineData::ByteStream(stream, info.metadata))
})
.map_err(|err| {
IoError::new_with_additional_context(err.kind(), info.span, None, "Could not spawn tee")
IoError::new_with_additional_context(err, info.span, None, "Could not spawn tee")
})?;
Ok(TeeThread { sender, thread })
@ -481,13 +483,8 @@ fn copy_on_thread(
Ok(())
})
.map_err(|err| {
IoError::new_with_additional_context(
err.kind(),
span,
None,
"Could not spawn stderr copier",
)
.into()
IoError::new_with_additional_context(err, span, None, "Could not spawn stderr copier")
.into()
})
}
@ -532,7 +529,7 @@ fn tee_forwards_errors_back_immediately() {
let slow_input = (0..100).inspect(|_| std::thread::sleep(Duration::from_millis(1)));
let iter = tee(slow_input, |_| {
Err(ShellError::Io(IoError::new_with_additional_context(
std::io::ErrorKind::Other,
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::Other),
Span::test_data(),
None,
"test",
@ -564,7 +561,7 @@ fn tee_waits_for_the_other_thread() {
std::thread::sleep(Duration::from_millis(10));
waited_clone.store(true, Ordering::Relaxed);
Err(ShellError::Io(IoError::new_with_additional_context(
std::io::ErrorKind::Other,
shell_error::io::ErrorKind::from_std(std::io::ErrorKind::Other),
Span::test_data(),
None,
"test",

View File

@ -134,7 +134,7 @@ fn read_json_lines(
.lines()
.filter(|line| line.as_ref().is_ok_and(|line| !line.trim().is_empty()) || line.is_err())
.map(move |line| {
let line = line.map_err(|err| IoError::new(err.kind(), span, None))?;
let line = line.map_err(|err| IoError::new(err, span, None))?;
if strict {
convert_string_to_value_strict(&line, span)
} else {

View File

@ -8,7 +8,7 @@ use std::{iter, sync::Arc};
fn make_csv_error(error: csv::Error, format_name: &str, head: Span) -> ShellError {
if let csv::ErrorKind::Io(error) = error.kind() {
IoError::new(error.kind(), head, None).into()
IoError::new(error, head, None).into()
} else {
ShellError::GenericError {
error: format!("Failed to generate {format_name} data"),

View File

@ -152,7 +152,7 @@ impl From<WriteError> for ShellError {
help: None,
inner: vec![],
},
WriteError::Io(err, span) => ShellError::Io(IoError::new(err.kind(), span, None)),
WriteError::Io(err, span) => ShellError::Io(IoError::new(err, span, None)),
WriteError::Shell(err) => *err,
}
}

View File

@ -95,7 +95,7 @@ impl Command for ToMsgpackz {
serialize_types,
)?;
out.flush()
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
.map_err(|err| IoError::new(err, call.head, None))?;
drop(out);
Ok(Value::binary(out_buf, call.head).into_pipeline_data())

View File

@ -55,13 +55,8 @@ impl Command for Source {
let cwd = engine_state.cwd_as_string(Some(stack))?;
let pb = std::path::PathBuf::from(block_id_name);
let parent = pb.parent().unwrap_or(std::path::Path::new(""));
let file_path = canonicalize_with(pb.as_path(), cwd).map_err(|err| {
IoError::new(
err.kind().not_found_as(NotFound::File),
call.head,
pb.clone(),
)
})?;
let file_path = canonicalize_with(pb.as_path(), cwd)
.map_err(|err| IoError::new(err.not_found_as(NotFound::File), call.head, pb.clone()))?;
// Note: We intentionally left out PROCESS_PATH since it's supposed to
// to work like argv[0] in C, which is the name of the program being executed.

View File

@ -374,9 +374,7 @@ fn send_multipart_request(
let mut builder = MultipartWriter::new();
let err = |e: std::io::Error| {
ShellErrorOrRequestError::ShellError(
IoError::new_with_additional_context(e.kind(), span, None, e).into(),
)
ShellErrorOrRequestError::ShellError(IoError::new(e, span, None).into())
};
for (col, val) in val.into_owned() {
@ -466,12 +464,7 @@ fn send_cancellable_request(
let _ = tx.send(ret); // may fail if the user has cancelled the operation
})
.map_err(|err| {
IoError::new_with_additional_context(
err.kind(),
span,
None,
"Could not spawn HTTP requester",
)
IoError::new_with_additional_context(err, span, None, "Could not spawn HTTP requester")
})
.map_err(ShellError::from)?;
@ -529,12 +522,7 @@ fn send_cancellable_request_bytes(
let _ = tx.send(ret);
})
.map_err(|err| {
IoError::new_with_additional_context(
err.kind(),
span,
None,
"Could not spawn HTTP requester",
)
IoError::new_with_additional_context(err, span, None, "Could not spawn HTTP requester")
})
.map_err(ShellError::from)?;
@ -685,7 +673,7 @@ fn handle_response_error(span: Span, requested_url: &str, response_err: Error) -
break 'io generic_network_failure();
};
ShellError::Io(IoError::new(io_error.kind(), span, None))
ShellError::Io(IoError::new(io_error, span, None))
}
_ => generic_network_failure(),
}

View File

@ -132,7 +132,7 @@ fn get_free_port(
}
Err(IoError::new_with_additional_context(
last_err.expect("range not empty, validated before").kind(),
last_err.expect("range not empty, validated before"),
range_span,
None,
"Every port has been tried, but no valid one was found",

View File

@ -153,7 +153,7 @@ fn exists(path: &Path, span: Span, args: &Arguments) -> Value {
Value::bool(
match exists {
Ok(exists) => exists,
Err(err) => return Value::error(IoError::new(err.kind(), span, path).into(), span),
Err(err) => return Value::error(IoError::new(err, span, path).into(), span),
},
span,
)

View File

@ -1,6 +1,9 @@
use nu_engine::command_prelude::*;
use nu_path::expand_path_with;
use nu_protocol::{engine::StateWorkingSet, shell_error::io::IoError};
use nu_protocol::{
engine::StateWorkingSet,
shell_error::{self, io::IoError},
};
#[derive(Clone)]
pub struct PathSelf;
@ -56,7 +59,7 @@ impl Command for PathSelf {
let cwd = working_set.permanent_state.cwd(None)?;
let current_file = working_set.files.top().ok_or_else(|| {
IoError::new_with_additional_context(
std::io::ErrorKind::NotFound,
shell_error::io::ErrorKind::FileNotFound,
call.head,
None,
"Couldn't find current file",
@ -67,7 +70,7 @@ impl Command for PathSelf {
let dir = expand_path_with(
current_file.parent().ok_or_else(|| {
IoError::new_with_additional_context(
std::io::ErrorKind::NotFound,
shell_error::io::ErrorKind::FileNotFound,
call.head,
current_file.to_owned(),
"Couldn't find current file's parent.",

View File

@ -108,7 +108,7 @@ fn path_type(path: &Path, span: Span, args: &Arguments) -> Value {
match path.symlink_metadata() {
Ok(metadata) => Value::string(get_file_type(&metadata), span),
Err(err) if err.kind() == io::ErrorKind::NotFound => Value::nothing(span),
Err(err) => Value::error(IoError::new(err.kind(), span, None).into(), span),
Err(err) => Value::error(IoError::new(err, span, None).into(), span),
}
}

View File

@ -77,7 +77,7 @@ impl FileInfo {
long,
})
}
Err(e) => Err(IoError::new(e.kind(), tag, path).into()),
Err(e) => Err(IoError::new(e, tag, path).into()),
}
}
}

View File

@ -7,7 +7,7 @@ use crossterm::{
};
use itertools::Itertools;
use nu_engine::command_prelude::*;
use nu_protocol::shell_error::io::IoError;
use nu_protocol::shell_error::{self, io::IoError};
use std::{io::Write, time::Duration};
@ -116,7 +116,9 @@ impl Command for Input {
crossterm::terminal::disable_raw_mode()
.map_err(&from_io_error)?;
return Err(IoError::new(
std::io::ErrorKind::Interrupted,
shell_error::io::ErrorKind::from_std(
std::io::ErrorKind::Interrupted,
),
call.head,
None,
)
@ -156,7 +158,7 @@ impl Command for Input {
terminal::Clear(ClearType::CurrentLine),
cursor::MoveToColumn(0),
)
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
.map_err(|err| IoError::new(err, call.head, None))?;
if let Some(prompt) = &prompt {
execute!(std::io::stdout(), Print(prompt.to_string()))
.map_err(&from_io_error)?;

View File

@ -84,7 +84,7 @@ There are 4 `key_type` variants:
let add_raw = call.has_flag(engine_state, stack, "raw")?;
let config = engine_state.get_config();
terminal::enable_raw_mode().map_err(|err| IoError::new(err.kind(), head, None))?;
terminal::enable_raw_mode().map_err(|err| IoError::new(err, head, None))?;
if config.use_kitty_protocol {
if let Ok(false) = crossterm::terminal::supports_keyboard_enhancement() {
@ -123,7 +123,7 @@ There are 4 `key_type` variants:
})?;
let event = parse_event(head, &event, &event_type_filter, add_raw);
if let Some(event) = event {
terminal::disable_raw_mode().map_err(|err| IoError::new(err.kind(), head, None))?;
terminal::disable_raw_mode().map_err(|err| IoError::new(err, head, None))?;
if config.use_kitty_protocol {
let _ = execute!(
std::io::stdout(),
@ -230,17 +230,17 @@ impl EventTypeFilter {
fn enable_events(&self, span: Span) -> Result<DeferredConsoleRestore, ShellError> {
if self.listen_mouse {
crossterm::execute!(stdout(), EnableMouseCapture)
.map_err(|err| IoError::new(err.kind(), span, None))?;
.map_err(|err| IoError::new(err, span, None))?;
}
if self.listen_paste {
crossterm::execute!(stdout(), EnableBracketedPaste)
.map_err(|err| IoError::new(err.kind(), span, None))?;
.map_err(|err| IoError::new(err, span, None))?;
}
if self.listen_focus {
crossterm::execute!(stdout(), crossterm::event::EnableFocusChange)
.map_err(|err| IoError::new(err.kind(), span, None))?;
.map_err(|err| IoError::new(err, span, None))?;
}
Ok(DeferredConsoleRestore {

View File

@ -142,12 +142,7 @@ impl Command for InputList {
.report(false)
.interact_on_opt(&Term::stderr())
.map_err(|dialoguer::Error::IO(err)| {
IoError::new_with_additional_context(
err.kind(),
call.head,
None,
INTERACT_ERROR,
)
IoError::new_with_additional_context(err, call.head, None, INTERACT_ERROR)
})?,
)
} else if fuzzy {
@ -164,12 +159,7 @@ impl Command for InputList {
.report(false)
.interact_on_opt(&Term::stderr())
.map_err(|dialoguer::Error::IO(err)| {
IoError::new_with_additional_context(
err.kind(),
call.head,
None,
INTERACT_ERROR,
)
IoError::new_with_additional_context(err, call.head, None, INTERACT_ERROR)
})?,
)
} else {
@ -185,12 +175,7 @@ impl Command for InputList {
.report(false)
.interact_on_opt(&Term::stderr())
.map_err(|dialoguer::Error::IO(err)| {
IoError::new_with_additional_context(
err.kind(),
call.head,
None,
INTERACT_ERROR,
)
IoError::new_with_additional_context(err, call.head, None, INTERACT_ERROR)
})?,
)
};

View File

@ -99,19 +99,17 @@ The `prefix` is not included in the output."
let prefix = prefix.unwrap_or_default();
let terminator: Option<Vec<u8>> = call.get_flag(engine_state, stack, "terminator")?;
crossterm::terminal::enable_raw_mode()
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
crossterm::terminal::enable_raw_mode().map_err(|err| IoError::new(err, call.head, None))?;
scopeguard::defer! {
let _ = crossterm::terminal::disable_raw_mode();
}
// clear terminal events
while crossterm::event::poll(Duration::from_secs(0))
.map_err(|err| IoError::new(err.kind(), call.head, None))?
.map_err(|err| IoError::new(err, call.head, None))?
{
// If there's an event, read it to remove it from the queue
let _ = crossterm::event::read()
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
let _ = crossterm::event::read().map_err(|err| IoError::new(err, call.head, None))?;
}
let mut b = [0u8; 1];
@ -122,17 +120,17 @@ The `prefix` is not included in the output."
let mut stdout = std::io::stdout().lock();
stdout
.write_all(&query)
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
.map_err(|err| IoError::new(err, call.head, None))?;
stdout
.flush()
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
.map_err(|err| IoError::new(err, call.head, None))?;
}
// Validate and skip prefix
for bc in prefix {
stdin
.read_exact(&mut b)
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
.map_err(|err| IoError::new(err, call.head, None))?;
if b[0] != bc {
return Err(ShellError::GenericError {
error: "Input did not begin with expected sequence".into(),
@ -151,7 +149,7 @@ The `prefix` is not included in the output."
loop {
stdin
.read_exact(&mut b)
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
.map_err(|err| IoError::new(err, call.head, None))?;
if b[0] == CTRL_C {
return Err(ShellError::InterruptedByUser {
@ -173,7 +171,7 @@ The `prefix` is not included in the output."
loop {
stdin
.read_exact(&mut b)
.map_err(|err| IoError::new(err.kind(), call.head, None))?;
.map_err(|err| IoError::new(err, call.head, None))?;
if b[0] == CTRL_C {
break;

View File

@ -255,7 +255,7 @@ fn parse_file_script(
match std::fs::read(path) {
Ok(contents) => parse_script(working_set, Some(&filename), &contents, is_debug, call_head),
Err(err) => Err(ShellError::Io(IoError::new(
err.kind().not_found_as(NotFound::File),
err.not_found_as(NotFound::File),
path_span,
PathBuf::from(path),
))),

View File

@ -93,7 +93,7 @@ fn registry_query(
let reg_hive = get_reg_hive(engine_state, stack, call)?;
let reg_key = reg_hive
.open_subkey(registry_key.item)
.map_err(|err| IoError::new(err.kind(), *registry_key_span, None))?;
.map_err(|err| IoError::new(err, *registry_key_span, None))?;
if registry_value.is_none() {
let mut reg_values = vec![];

View File

@ -205,11 +205,11 @@ impl Command for External {
let stderr = stack.stderr();
let merged_stream = if matches!(stdout, OutDest::Pipe) && matches!(stderr, OutDest::Pipe) {
let (reader, writer) =
os_pipe::pipe().map_err(|err| IoError::new(err.kind(), call.head, None))?;
os_pipe::pipe().map_err(|err| IoError::new(err, call.head, None))?;
command.stdout(
writer
.try_clone()
.map_err(|err| IoError::new(err.kind(), call.head, None))?,
.map_err(|err| IoError::new(err, call.head, None))?,
);
command.stderr(writer);
Some(reader)
@ -220,8 +220,7 @@ impl Command for External {
command.stdout(Stdio::null());
} else {
command.stdout(
Stdio::try_from(stdout)
.map_err(|err| IoError::new(err.kind(), call.head, None))?,
Stdio::try_from(stdout).map_err(|err| IoError::new(err, call.head, None))?,
);
}
@ -231,8 +230,7 @@ impl Command for External {
command.stderr(Stdio::null());
} else {
command.stderr(
Stdio::try_from(stderr)
.map_err(|err| IoError::new(err.kind(), call.head, None))?,
Stdio::try_from(stderr).map_err(|err| IoError::new(err, call.head, None))?,
);
}
@ -280,7 +278,7 @@ impl Command for External {
let mut child = child.map_err(|err| {
IoError::new_internal(
err.kind(),
err,
"Could not spawn foreground child",
nu_protocol::location!(),
)
@ -290,7 +288,7 @@ impl Command for External {
if !thread_job.try_add_pid(child.pid()) {
kill_by_pid(child.pid().into()).map_err(|err| {
ShellError::Io(IoError::new_internal(
err.kind(),
err,
"Could not spawn external stdin worker",
nu_protocol::location!(),
))
@ -310,7 +308,7 @@ impl Command for External {
})
.map_err(|err| {
IoError::new_with_additional_context(
err.kind(),
err,
call.head,
None,
"Could not spawn external stdin worker",
@ -498,7 +496,7 @@ fn write_pipeline_data(
} else if let PipelineData::Value(Value::Binary { val, .. }, ..) = data {
writer.write_all(&val).map_err(|err| {
IoError::new_internal(
err.kind(),
err,
"Could not write pipeline data",
nu_protocol::location!(),
)
@ -518,7 +516,7 @@ fn write_pipeline_data(
let bytes = value.coerce_into_binary()?;
writer.write_all(&bytes).map_err(|err| {
IoError::new_internal(
err.kind(),
err,
"Could not write pipeline data",
nu_protocol::location!(),
)

View File

@ -518,7 +518,7 @@ fn pretty_hex_stream(stream: ByteStream, span: Span) -> ByteStream {
(&mut reader)
.take(cfg.width as u64)
.read_to_end(&mut read_buf)
.map_err(|err| IoError::new(err.kind(), span, None))?;
.map_err(|err| IoError::new(err, span, None))?;
if !read_buf.is_empty() {
nu_pretty_hex::hex_write(&mut write_buf, &read_buf, cfg, Some(true))

View File

@ -60,5 +60,5 @@ fn self_path_runtime() {
fn self_path_repl() {
let actual = nu!("const foo = path self; $foo");
assert!(!actual.status.success());
assert!(actual.err.contains("nu::shell::io::not_found"));
assert!(actual.err.contains("nu::shell::io::file_not_found"));
}

View File

@ -6,6 +6,8 @@ use nu_test_support::playground::Playground;
use rstest::rstest;
#[cfg(not(windows))]
use std::fs;
#[cfg(windows)]
use std::{fs::OpenOptions, os::windows::fs::OpenOptionsExt};
#[test]
fn removes_a_file() {
@ -562,3 +564,26 @@ fn rm_with_tilde() {
assert!(!files_exist_at(&["~tilde"], dirs.test()));
})
}
#[test]
#[cfg(windows)]
fn rm_already_in_use() {
Playground::setup("rm_already_in_use", |dirs, sandbox| {
sandbox.with_files(&[EmptyFile("i_will_be_used.txt")]);
let file_path = dirs.root().join("rm_already_in_use/i_will_be_used.txt");
let _file = OpenOptions::new()
.read(true)
.write(false)
.share_mode(0) // deny all sharing
.open(file_path)
.unwrap();
let outcome = nu!(
cwd: dirs.root(),
"rm rm_already_in_use/i_will_be_used.txt"
);
assert!(outcome.err.contains("nu::shell::io::already_in_use"));
})
}