arg: add support for dereference

This commit is contained in:
zwPapEr 2020-08-11 00:49:19 +08:00 committed by Abin Simon
parent 8e1662d5e9
commit faea1c0051
11 changed files with 76 additions and 38 deletions

View file

@ -217,6 +217,13 @@ pub fn build() -> App<'static, 'static> {
.multiple(true)
.help("Display the index number of each file"),
)
.arg(
Arg::with_name("dereference")
.short("L")
.long("dereference")
.multiple(true)
.help("When showing file information for a symbolic link, show information for the file the link references rather than for the link itself"),
)
}
fn validate_date_argument(arg: String) -> Result<(), String> {

View file

@ -52,10 +52,7 @@ pub enum Elem {
impl Elem {
pub fn has_suid(&self) -> bool {
match self {
Elem::Dir { uid: true } | Elem::File { uid: true, .. } => true,
_ => false,
}
matches!(self, Elem::Dir { uid: true } | Elem::File { uid: true, .. })
}
}

View file

@ -82,7 +82,7 @@ impl Core {
};
for path in paths {
let mut meta = match Meta::from_path(&path) {
let mut meta = match Meta::from_path(&path, self.flags.dereference) {
Ok(meta) => meta,
Err(err) => {
print_error!("lsd: {}: {}\n", path.display(), err);
@ -95,7 +95,12 @@ impl Core {
meta_list.push(meta);
}
_ => {
match meta.recurse_into(depth, self.flags.display, &self.flags.ignore_globs) {
match meta.recurse_into(
depth,
self.flags.display,
&self.flags.ignore_globs,
self.flags.dereference,
) {
Ok(content) => {
meta.content = content;
meta_list.push(meta);

View file

@ -221,10 +221,7 @@ fn should_display_folder_path(depth: usize, metas: &[Meta]) -> bool {
} else {
let folder_number = metas
.iter()
.filter(|x| match x.file_type {
FileType::Directory { .. } => true,
_ => false,
})
.filter(|x| matches!(x.file_type, FileType::Directory { .. }))
.count();
folder_number > 1 || folder_number < metas.len()
@ -270,7 +267,7 @@ fn get_output<'a>(
Block::SizeValue => strings.push(meta.size.render_value(colors, flags)),
Block::Date => strings.push(meta.date.render(colors, &flags)),
Block::Name => {
let s: String = if flags.no_symlink {
let s: String = if flags.no_symlink || flags.dereference {
ANSIStrings(&[
meta.name.render(colors, icons, &display_option),
meta.indicator.render(&flags),

View file

@ -22,6 +22,7 @@ pub struct Flags {
pub no_symlink: bool,
pub total_size: bool,
pub ignore_globs: GlobSet,
pub dereference: bool,
}
impl Flags {
@ -34,6 +35,7 @@ impl Flags {
let date_inputs: Vec<&str> = matches.values_of("date").unwrap().collect();
let dir_order_inputs: Vec<&str> = matches.values_of("group-dirs").unwrap().collect();
let ignore_globs_inputs: Vec<&str> = matches.values_of("ignore-glob").unwrap().collect();
let dereference = matches.is_present("dereference");
// inode set layout to oneline and blocks to inode,name
let inode = matches.is_present("inode");
let blocks_inputs: Vec<&str> = if let Some(blocks) = matches.values_of("blocks") {
@ -179,6 +181,7 @@ impl Flags {
no_symlink: matches.is_present("no-symlink"),
total_size: matches.is_present("total-size"),
inode,
dereference,
})
}
}
@ -204,6 +207,7 @@ impl Default for Flags {
total_size: false,
ignore_globs: GlobSet::empty(),
inode: false,
dereference: false,
}
}
}

View file

@ -342,7 +342,7 @@ mod test {
let tmp_dir = tempdir().expect("failed to create temp dir");
let file_path = tmp_dir.path().join("file.txt");
File::create(&file_path).expect("failed to create file");
let meta = Meta::from_path(&file_path).unwrap();
let meta = Meta::from_path(&file_path, false).unwrap();
let icon = Icons::new(Theme::NoIcon);
let icon = icon.get(&meta.name);
@ -355,7 +355,7 @@ mod test {
let tmp_dir = tempdir().expect("failed to create temp dir");
let file_path = tmp_dir.path().join("file");
File::create(&file_path).expect("failed to create file");
let meta = Meta::from_path(&file_path).unwrap();
let meta = Meta::from_path(&file_path, false).unwrap();
let icon = Icons::new(Theme::Fancy);
let icon = icon.get(&meta.name);
@ -368,7 +368,7 @@ mod test {
let tmp_dir = tempdir().expect("failed to create temp dir");
let file_path = tmp_dir.path().join("file");
File::create(&file_path).expect("failed to create file");
let meta = Meta::from_path(&file_path).unwrap();
let meta = Meta::from_path(&file_path, false).unwrap();
let icon = Icons::new(Theme::Unicode);
let icon = icon.get(&meta.name);
@ -380,7 +380,7 @@ mod test {
fn get_directory_icon() {
let tmp_dir = tempdir().expect("failed to create temp dir");
let file_path = tmp_dir.path();
let meta = Meta::from_path(&file_path.to_path_buf()).unwrap();
let meta = Meta::from_path(&file_path.to_path_buf(), false).unwrap();
let icon = Icons::new(Theme::Fancy);
let icon = icon.get(&meta.name);
@ -392,7 +392,7 @@ mod test {
fn get_directory_icon_unicode() {
let tmp_dir = tempdir().expect("failed to create temp dir");
let file_path = tmp_dir.path();
let meta = Meta::from_path(&file_path.to_path_buf()).unwrap();
let meta = Meta::from_path(&file_path.to_path_buf(), false).unwrap();
let icon = Icons::new(Theme::Unicode);
let icon = icon.get(&meta.name);
@ -404,7 +404,7 @@ mod test {
fn get_directory_icon_with_ext() {
let tmp_dir = tempdir().expect("failed to create temp dir");
let file_path = tmp_dir.path();
let meta = Meta::from_path(&file_path.to_path_buf()).unwrap();
let meta = Meta::from_path(&file_path.to_path_buf(), false).unwrap();
let icon = Icons::new(Theme::Fancy);
let icon = icon.get(&meta.name);
@ -419,7 +419,7 @@ mod test {
for (file_name, file_icon) in &Icons::get_default_icons_by_name() {
let file_path = tmp_dir.path().join(file_name);
File::create(&file_path).expect("failed to create file");
let meta = Meta::from_path(&file_path).unwrap();
let meta = Meta::from_path(&file_path, false).unwrap();
let icon = Icons::new(Theme::Fancy);
let icon = icon.get(&meta.name);
@ -435,7 +435,7 @@ mod test {
for (ext, file_icon) in &Icons::get_default_icons_by_extension() {
let file_path = tmp_dir.path().join(format!("file.{}", ext));
File::create(&file_path).expect("failed to create file");
let meta = Meta::from_path(&file_path).unwrap();
let meta = Meta::from_path(&file_path, false).unwrap();
let icon = Icons::new(Theme::Fancy);
let icon = icon.get(&meta.name);

View file

@ -137,8 +137,8 @@ mod test {
#[test]
fn test_dir_type() {
let tmp_dir = tempdir().expect("failed to create temp dir");
let meta =
Meta::from_path(&tmp_dir.path().to_path_buf()).expect("failed to get tempdir path");
let meta = Meta::from_path(&tmp_dir.path().to_path_buf(), false)
.expect("failed to get tempdir path");
let metadata = tmp_dir.path().metadata().expect("failed to get metas");
let colors = Colors::new(Theme::NoLscolors);

View file

@ -51,6 +51,7 @@ impl Meta {
depth: usize,
display: Display,
ignore_globs: &GlobSet,
dereference: bool,
) -> Result<Option<Vec<Meta>>, std::io::Error> {
if depth == 0 {
return Ok(None);
@ -81,7 +82,7 @@ impl Meta {
current_meta = self.clone();
current_meta.name.name = ".".to_owned();
let parent_meta = Self::from_path(&self.path.join(Component::ParentDir))?;
let parent_meta = Self::from_path(&self.path.join(Component::ParentDir), dereference)?;
content.push(current_meta);
content.push(parent_meta);
@ -104,7 +105,7 @@ impl Meta {
}
}
let mut entry_meta = match Self::from_path(&path) {
let mut entry_meta = match Self::from_path(&path, dereference) {
Ok(res) => res,
Err(err) => {
print_error!("lsd: {}: {}\n", path.display(), err);
@ -112,7 +113,7 @@ impl Meta {
}
};
match entry_meta.recurse_into(depth - 1, display, ignore_globs) {
match entry_meta.recurse_into(depth - 1, display, ignore_globs, dereference) {
Ok(content) => entry_meta.content = content,
Err(err) => {
print_error!("lsd: {}: {}\n", path.display(), err);
@ -186,9 +187,9 @@ impl Meta {
}
}
pub fn from_path(path: &Path) -> Result<Self, std::io::Error> {
pub fn from_path(path: &Path, dereference: bool) -> Result<Self, std::io::Error> {
// If the file is a link then retrieve link metadata instead with target metadata (if present).
let (metadata, symlink_meta) = if read_link(path).is_ok() {
let (metadata, symlink_meta) = if read_link(path).is_ok() && !dereference {
(path.symlink_metadata()?, path.metadata().ok())
} else {
(path.metadata()?, None)

View file

@ -216,7 +216,7 @@ mod test {
// Chreate the directory
let dir_path = tmp_dir.path().join("directory");
fs::create_dir(&dir_path).expect("failed to create the dir");
let meta = Meta::from_path(&dir_path).unwrap();
let meta = Meta::from_path(&dir_path, false).unwrap();
let colors = Colors::new(color::Theme::NoLscolors);
@ -316,7 +316,7 @@ mod test {
// Create the file;
let file_path = tmp_dir.path().join("file.txt");
File::create(&file_path).expect("failed to create file");
let meta = Meta::from_path(&file_path).unwrap();
let meta = Meta::from_path(&file_path, false).unwrap();
let colors = Colors::new(color::Theme::NoColor);

View file

@ -139,12 +139,12 @@ mod tests {
// Create the file;
let path_a = tmp_dir.path().join("zzz");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let meta_a = Meta::from_path(&path_a, false).expect("failed to get meta");
// Create a dir;
let path_z = tmp_dir.path().join("aaa");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::First;
@ -164,12 +164,12 @@ mod tests {
// Create the file;
let path_a = tmp_dir.path().join("zzz");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let meta_a = Meta::from_path(&path_a, false).expect("failed to get meta");
// Create a dir;
let path_z = tmp_dir.path().join("aaa");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::Last;
@ -188,12 +188,12 @@ mod tests {
// Create the file;
let path_a = tmp_dir.path().join("aaa");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let meta_a = Meta::from_path(&path_a, false).expect("failed to get meta");
// Create a dir;
let path_z = tmp_dir.path().join("zzz");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::None;
@ -213,12 +213,12 @@ mod tests {
// Create the file;
let path_a = tmp_dir.path().join("zzz");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let meta_a = Meta::from_path(&path_a, false).expect("failed to get meta");
// Create a dir;
let path_z = tmp_dir.path().join("aaa");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::None;
@ -238,7 +238,7 @@ mod tests {
// Create the file;
let path_a = tmp_dir.path().join("aaa");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let meta_a = Meta::from_path(&path_a, false).expect("failed to get meta");
// Create the file;
let path_z = tmp_dir.path().join("zzz");
@ -264,7 +264,7 @@ mod tests {
.success();
assert_eq!(true, success, "failed to change file timestamp");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
let mut flags = Flags::default();
flags.sort_by = SortFlag::Time;

View file

@ -157,6 +157,33 @@ fn test_list_broken_link_ok() {
.stderr(predicate::str::contains(matched).not());
}
#[cfg(unix)]
#[test]
fn test_dereference_link_right_type_and_no_link() {
let dir = tempdir();
dir.child("target").touch().unwrap();
let link = dir.path().join("link");
let file_type = ".rw";
let link_icon = "";
fs::symlink("target", &link).unwrap();
cmd()
.arg("-l")
.arg("--dereference")
.arg(&link)
.assert()
.stdout(predicate::str::starts_with(file_type))
.stdout(predicate::str::contains(link_icon).not());
cmd()
.arg("-l")
.arg("-L")
.arg(link)
.assert()
.stdout(predicate::str::starts_with(file_type))
.stdout(predicate::str::contains(link_icon).not());
}
fn cmd() -> Command {
Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap()
}