make ls -lf outputs full path in symbolic target (#13605)

# Description
Fixes: #13479 

# User-Facing Changes
Given the following setup:
```
cd /tmp
touch src_file.txt
ln -s src_file.txt link1
```
### Before 
```
ls -lf link1 | get target.0  # It outputs src_file.txt
```
### After
```
ls -lf link1 | get target.0  # It outputs /tmp/src_file.txt
```
# Tests + Formatting
Added a test for the change
This commit is contained in:
Wind 2024-08-13 19:34:10 +08:00 committed by GitHub
parent 48e401834d
commit a55d172e52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 2 deletions

View File

@ -5,7 +5,7 @@ use nu_engine::glob_from;
#[allow(deprecated)]
use nu_engine::{command_prelude::*, env::current_dir};
use nu_glob::MatchOptions;
use nu_path::expand_to_real_path;
use nu_path::{expand_path_with, expand_to_real_path};
use nu_protocol::{DataSource, NuGlob, PipelineMetadata, Signals};
use pathdiff::diff_paths;
@ -412,6 +412,7 @@ fn ls_for_one_pattern(
du,
&signals,
use_mime_type,
args.full_paths,
);
match entry {
Ok(value) => Some(value),
@ -522,6 +523,7 @@ pub(crate) fn dir_entry_dict(
du: bool,
signals: &Signals,
use_mime_type: bool,
full_symlink_target: bool,
) -> Result<Value, ShellError> {
#[cfg(windows)]
if metadata.is_none() {
@ -551,7 +553,23 @@ pub(crate) fn dir_entry_dict(
"target",
if md.file_type().is_symlink() {
if let Ok(path_to_link) = filename.read_link() {
Value::string(path_to_link.to_string_lossy(), span)
// Actually `filename` should always have a parent because it's a symlink.
// But for safety, we check `filename.parent().is_some()` first.
if full_symlink_target && filename.parent().is_some() {
Value::string(
expand_path_with(
path_to_link,
filename
.parent()
.expect("already check the filename have a parent"),
true,
)
.to_string_lossy(),
span,
)
} else {
Value::string(path_to_link.to_string_lossy(), span)
}
} else {
Value::string("Could not obtain target file's path", span)
}

View File

@ -808,3 +808,28 @@ fn list_inside_tilde_glob_metachars_dir() {
},
);
}
#[test]
fn list_symlink_with_full_path() {
Playground::setup("list_symlink_with_full_path", |dirs, sandbox| {
sandbox.with_files(&[EmptyFile("test_file.txt")]);
#[cfg(unix)]
let _ = std::os::unix::fs::symlink("test_file.txt", dirs.test().join("test_link1"));
#[cfg(windows)]
let _ = std::os::windows::fs::symlink_file("test_file.txt", dirs.test().join("test_link1"));
let actual = nu!(
cwd: dirs.test(),
"ls -l test_link1 | get target.0"
);
assert_eq!(actual.out, "test_file.txt");
let actual = nu!(
cwd: dirs.test(),
"ls -lf test_link1 | get target.0"
);
assert_eq!(
actual.out,
dirs.test().join("test_file.txt").to_string_lossy()
);
})
}