use crate::Cmd; use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint}; use std::{fs, path::PathBuf}; #[derive(Debug, Default)] pub struct Readlink; impl Cmd for Readlink { fn cli(&self) -> clap::Command { Command::new("readlink") .about("Print symbolic link target or canonical file name") .version(env!("CARGO_PKG_VERSION")) .author("Nathan Fisher") .args([ Arg::new("path") .value_name("PATH") .value_hint(ValueHint::AnyPath) .num_args(1..) .required(true), Arg::new("canon") .help("Canonicalize path") .short('f') .visible_short_alias('c') .long("canonicalize") .action(ArgAction::SetTrue), Arg::new("newline") .help("Do not print the terminating newline.") .short('n') .long("no-newline") .action(ArgAction::SetTrue), ]) } fn run(&self, matches: &ArgMatches) -> Result<(), Box> { if let Some(paths) = matches.get_many::("path") { let paths: Vec<_> = paths.collect(); let len = paths.len(); if matches.get_flag("newline") && len > 1 { eprintln!("readlink: ignoring --no-newline with multiple arguments"); } for p in paths { let path = if matches.get_flag("canon") { PathBuf::from(p).canonicalize()? } else { fs::read_link(p)? }; print!("{}", path.display()); if !matches.get_flag("newline") || len > 1 { println!(); } } } Ok(()) } fn path(&self) -> Option { Some(crate::Path::UsrBin) } }