Small fixes and refactors to paths & source command (#3998)

* Expand path when converting value -> PathBuf

Also includes Tagged<PathBuf>.

Fixes #3605

* Expand path for PATH env. variable

Fixes #1834

* Remove leftover Cows after nu-path refactor

There were some unnecessary Cow conversions leftover from the old
nu-path implementation.

* Use canonicalize in source command; Improve errors

Previously, `source` used `expand_path()` which does not follow
symlinks.

As a follow up, I improved the source error messages so they now tell
why the source file could not be canonicalized or read into string.
This commit is contained in:
Jakub Žádník
2021-09-12 02:36:14 +03:00
committed by GitHub
parent 0fa0c25fb3
commit cc5c4d38bb
6 changed files with 55 additions and 36 deletions

View File

@ -1,11 +1,11 @@
use crate::{lex::tokens::LiteCommand, ParserScope};
use nu_errors::{ArgumentError, ParseError};
use nu_path::expand_path;
use nu_path::{canonicalize, canonicalize_with};
use nu_protocol::hir::{Expression, InternalCommand};
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use nu_source::SpannedItem;
pub fn parse_source_internal(
lite_cmd: &LiteCommand,
@ -37,14 +37,14 @@ fn find_source_file(
command: &InternalCommand,
scope: &dyn ParserScope,
) -> Result<(), ParseError> {
let file = if let Some(ref positional_args) = command.args.positional {
let (file, file_span) = if let Some(ref positional_args) = command.args.positional {
if let Expression::FilePath(ref p) = positional_args[0].expr {
p
(p.as_path(), &positional_args[0].span)
} else {
Path::new(&lite_cmd.parts[1].item)
(Path::new(&lite_cmd.parts[1].item), &lite_cmd.parts[1].span)
}
} else {
Path::new(&lite_cmd.parts[1].item)
(Path::new(&lite_cmd.parts[1].item), &lite_cmd.parts[1].span)
};
let lib_dirs = nu_data::config::config(nu_source::Tag::unknown())
@ -61,25 +61,33 @@ fn find_source_file(
if let Some(dir) = lib_dirs {
for lib_path in dir.into_iter().flatten() {
let path = PathBuf::from(lib_path).join(&file);
let path = canonicalize_with(&file, lib_path).map_err(|e| {
ParseError::general_error(
format!("Can't load source file. Reason: {}", e.to_string()),
"Can't load this file".spanned(file_span),
)
})?;
if let Ok(contents) =
std::fs::read_to_string(&expand_path(Cow::Borrowed(path.as_path())))
{
if let Ok(contents) = std::fs::read_to_string(&path) {
return parse(&contents, 0, scope);
}
}
}
let path = Path::new(&file);
let path = canonicalize(&file).map_err(|e| {
ParseError::general_error(
format!("Can't load source file. Reason: {}", e.to_string()),
"Can't load this file".spanned(file_span),
)
})?;
let contents = std::fs::read_to_string(&expand_path(Cow::Borrowed(path)));
let contents = std::fs::read_to_string(&path);
match contents {
Ok(contents) => parse(&contents, 0, scope),
Err(_) => Err(ParseError::argument_error(
lite_cmd.parts[1].clone(),
ArgumentError::BadValue("can't load source file".into()),
Err(e) => Err(ParseError::general_error(
format!("Can't load source file. Reason: {}", e.to_string()),
"Can't load this file".spanned(file_span),
)),
}
}