From 9ec6d0c90e2ac442865a2914c3c7a4561555b611 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Tue, 28 Jan 2020 01:48:41 -0500 Subject: [PATCH] Add `--with-symlink-targets` option for the `ls` command that displays a new column for the target files of symlinks (#1292) * Add `--with-symlink-targets` option for the `ls` command that displays a new column for the target files of symlinks * Fix clippy warning Co-authored-by: Jonathan Turner --- src/commands/ls.rs | 6 ++++++ src/data/files.rs | 17 +++++++++++++++++ src/shell/filesystem_shell.rs | 5 +++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 18ee5ae74..06c378f39 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -13,6 +13,8 @@ pub struct LsArgs { pub full: bool, #[serde(rename = "short-names")] pub short_names: bool, + #[serde(rename = "with-symlink-targets")] + pub with_symlink_targets: bool, } impl PerItemCommand for Ls { @@ -29,6 +31,10 @@ impl PerItemCommand for Ls { ) .switch("full", "list all available columns for each entry") .switch("short-names", "only print the file names and not the path") + .switch( + "with-symlink-targets", + "display the paths to the target files that symlinks point to", + ) } fn usage(&self) -> &str { diff --git a/src/data/files.rs b/src/data/files.rs index 89ae02c35..a0601c8b5 100644 --- a/src/data/files.rs +++ b/src/data/files.rs @@ -7,6 +7,7 @@ pub(crate) fn dir_entry_dict( metadata: &std::fs::Metadata, tag: impl Into, full: bool, + with_symlink_targets: bool, ) -> Result { let mut dict = TaggedDictBuilder::new(tag); dict.insert_untagged("name", UntaggedValue::string(filename.to_string_lossy())); @@ -19,6 +20,22 @@ pub(crate) fn dir_entry_dict( dict.insert_untagged("type", UntaggedValue::string("Symlink")); }; + if full || with_symlink_targets { + if metadata.is_dir() || metadata.is_file() { + dict.insert_untagged("target", UntaggedValue::bytes(0u64)); + } else if let Ok(path_to_link) = filename.read_link() { + dict.insert_untagged( + "target", + UntaggedValue::string(path_to_link.to_string_lossy()), + ); + } else { + dict.insert_untagged( + "target", + UntaggedValue::string("Could not obtain target file's path"), + ); + } + } + if full { dict.insert_untagged( "readonly", diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index 9c7fabb2b..d0139a431 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -92,6 +92,7 @@ impl Shell for FilesystemShell { path, full, short_names, + with_symlink_targets, }: LsArgs, context: &RunnablePerItemContext, ) -> Result { @@ -166,7 +167,7 @@ impl Shell for FilesystemShell { } } - let value = dir_entry_dict(filename, &metadata, &name_tag, full)?; + let value = dir_entry_dict(filename, &metadata, &name_tag, full, with_symlink_targets)?; yield ReturnSuccess::value(value); } } @@ -217,7 +218,7 @@ impl Shell for FilesystemShell { } } - if let Ok(value) = dir_entry_dict(filename, &metadata, &name_tag, full) { + if let Ok(value) = dir_entry_dict(filename, &metadata, &name_tag, full, with_symlink_targets) { yield ReturnSuccess::value(value); } }