Fix path type using PWD from the environment (#12975)

This PR fixes the `path type` command so that it resolves relative paths
using PWD from the engine state.

As a bonus, it also fixes the issue of `path type` returning an empty
string instead of an error when it fails.
This commit is contained in:
YizhePKU 2024-05-27 01:23:52 +08:00 committed by GitHub
parent f38f88d42c
commit a1fc41db22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 23 deletions

View File

@ -1,10 +1,11 @@
use super::PathSubcommandArguments; use super::PathSubcommandArguments;
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_path::expand_tilde;
use nu_protocol::engine::StateWorkingSet; use nu_protocol::engine::StateWorkingSet;
use std::path::Path; use std::path::{Path, PathBuf};
struct Arguments; struct Arguments {
pwd: PathBuf,
}
impl PathSubcommandArguments for Arguments {} impl PathSubcommandArguments for Arguments {}
@ -45,19 +46,21 @@ If nothing is found, an empty string will be returned."#
fn run( fn run(
&self, &self,
engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let head = call.head; let head = call.head;
let args = Arguments; let args = Arguments {
pwd: engine_state.cwd(Some(stack))?,
};
// This doesn't match explicit nulls // This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) { if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head }); return Err(ShellError::PipelineEmpty { dst_span: head });
} }
input.map( input.map(
move |value| super::operate(&r#type, &args, value, head), move |value| super::operate(&path_type, &args, value, head),
engine_state.ctrlc.clone(), engine_state.ctrlc.clone(),
) )
} }
@ -69,14 +72,16 @@ If nothing is found, an empty string will be returned."#
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let head = call.head; let head = call.head;
let args = Arguments; let args = Arguments {
pwd: working_set.permanent().cwd(None)?,
};
// This doesn't match explicit nulls // This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) { if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head }); return Err(ShellError::PipelineEmpty { dst_span: head });
} }
input.map( input.map(
move |value| super::operate(&r#type, &args, value, head), move |value| super::operate(&path_type, &args, value, head),
working_set.permanent().ctrlc.clone(), working_set.permanent().ctrlc.clone(),
) )
} }
@ -97,21 +102,12 @@ If nothing is found, an empty string will be returned."#
} }
} }
fn r#type(path: &Path, span: Span, _: &Arguments) -> Value { fn path_type(path: &Path, span: Span, args: &Arguments) -> Value {
let meta = if path.starts_with("~") { let path = nu_path::expand_path_with(path, &args.pwd, true);
let p = expand_tilde(path); match std::fs::symlink_metadata(path) {
std::fs::symlink_metadata(p) Ok(metadata) => Value::string(get_file_type(&metadata), span),
} else { Err(err) => Value::error(err.into(), span),
std::fs::symlink_metadata(path) }
};
Value::string(
match &meta {
Ok(data) => get_file_type(data),
Err(_) => "",
},
span,
)
} }
fn get_file_type(md: &std::fs::Metadata) -> &str { fn get_file_type(md: &std::fs::Metadata) -> &str {

View File

@ -74,3 +74,14 @@ fn returns_type_of_existing_file_const() {
assert_eq!(actual.out, "dir"); assert_eq!(actual.out, "dir");
}) })
} }
#[test]
fn respects_cwd() {
Playground::setup("path_type_respects_cwd", |dirs, sandbox| {
sandbox.within("foo").with_files(&[EmptyFile("bar.txt")]);
let actual = nu!(cwd: dirs.test(), "cd foo; 'bar.txt' | path type");
assert_eq!(actual.out, "file");
})
}