1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

cp: Use PathBuf instead of String for paths

I think this should avoid unnecessarily validating utf-8, and avoids a few allocations.
This commit is contained in:
Thayne McCombs 2023-02-12 01:36:13 -07:00
parent 8678530095
commit 3acd75bcc4

View file

@ -26,7 +26,7 @@ use std::os::unix::fs::{FileTypeExt, PermissionsExt};
use std::path::{Path, PathBuf, StripPrefixError}; use std::path::{Path, PathBuf, StripPrefixError};
use std::string::ToString; use std::string::ToString;
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use clap::{builder::ValueParser, crate_version, Arg, ArgAction, ArgMatches, Command};
use filetime::FileTime; use filetime::FileTime;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
#[cfg(unix)] #[cfg(unix)]
@ -91,7 +91,7 @@ quick_error! {
/// Invalid arguments to backup /// Invalid arguments to backup
Backup(description: String) { display("{}\nTry '{} --help' for more information.", description, uucore::execution_phrase()) } Backup(description: String) { display("{}\nTry '{} --help' for more information.", description, uucore::execution_phrase()) }
NotADirectory(path: String) { display("'{}' is not a directory", path) } NotADirectory(path: PathBuf) { display("'{}' is not a directory", path.display()) }
} }
} }
@ -222,7 +222,7 @@ pub struct Options {
attributes: Attributes, attributes: Attributes,
recursive: bool, recursive: bool,
backup_suffix: String, backup_suffix: String,
target_dir: Option<String>, target_dir: Option<PathBuf>,
update: bool, update: bool,
verbose: bool, verbose: bool,
progress_bar: bool, progress_bar: bool,
@ -302,6 +302,7 @@ pub fn uu_app() -> Command {
.long(options::TARGET_DIRECTORY) .long(options::TARGET_DIRECTORY)
.value_name(options::TARGET_DIRECTORY) .value_name(options::TARGET_DIRECTORY)
.value_hint(clap::ValueHint::DirPath) .value_hint(clap::ValueHint::DirPath)
.value_parser(ValueParser::path_buf())
.help("copy all SOURCE arguments into target-directory"), .help("copy all SOURCE arguments into target-directory"),
) )
.arg( .arg(
@ -555,7 +556,8 @@ pub fn uu_app() -> Command {
.arg( .arg(
Arg::new(options::PATHS) Arg::new(options::PATHS)
.action(ArgAction::Append) .action(ArgAction::Append)
.value_hint(clap::ValueHint::AnyPath), .value_hint(clap::ValueHint::AnyPath)
.value_parser(ValueParser::path_buf()),
) )
} }
@ -576,7 +578,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
clap::error::ErrorKind::DisplayVersion => print!("{}", app.render_version()), clap::error::ErrorKind::DisplayVersion => print!("{}", app.render_version()),
_ => return Err(Box::new(e.with_exit_code(1))), _ => return Err(Box::new(e.with_exit_code(1))),
}; };
} else if let Ok(matches) = matches { } else if let Ok(mut matches) = matches {
let options = Options::from_matches(&matches)?; let options = Options::from_matches(&matches)?;
if options.overwrite == OverwriteMode::NoClobber && options.backup != BackupMode::NoBackup { if options.overwrite == OverwriteMode::NoClobber && options.backup != BackupMode::NoBackup {
@ -586,12 +588,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
)); ));
} }
let paths: Vec<String> = matches let paths: Vec<PathBuf> = matches
.get_many::<String>(options::PATHS) .remove_many::<PathBuf>(options::PATHS)
.map(|v| v.map(ToString::to_string).collect()) .map(|v| v.collect())
.unwrap_or_default(); .unwrap_or_default();
let (sources, target) = parse_path_args(&paths, &options)?; let (sources, target) = parse_path_args(paths, &options)?;
if let Err(error) = copy(&sources, &target, &options) { if let Err(error) = copy(&sources, &target, &options) {
match error { match error {
@ -754,11 +756,11 @@ impl Options {
// Parse target directory options // Parse target directory options
let no_target_dir = matches.get_flag(options::NO_TARGET_DIRECTORY); let no_target_dir = matches.get_flag(options::NO_TARGET_DIRECTORY);
let target_dir = matches let target_dir = matches
.get_one::<String>(options::TARGET_DIRECTORY) .get_one::<PathBuf>(options::TARGET_DIRECTORY)
.map(ToString::to_string); .cloned();
if let Some(dir) = &target_dir { if let Some(dir) = &target_dir {
if !Path::new(dir).is_dir() { if !dir.is_dir() {
return Err(Error::NotADirectory(dir.clone())); return Err(Error::NotADirectory(dir.clone()));
} }
}; };
@ -915,9 +917,7 @@ impl TargetType {
} }
/// Returns tuple of (Source paths, Target) /// Returns tuple of (Source paths, Target)
fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<Source>, Target)> { fn parse_path_args(mut paths: Vec<Source>, options: &Options) -> CopyResult<(Vec<Source>, Target)> {
let mut paths = path_args.iter().map(PathBuf::from).collect::<Vec<_>>();
if paths.is_empty() { if paths.is_empty() {
// No files specified // No files specified
return Err("missing file operand".into()); return Err("missing file operand".into());
@ -933,7 +933,7 @@ fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<S
Some(ref target) => { Some(ref target) => {
// All path args are sources, and the target dir was // All path args are sources, and the target dir was
// specified separately // specified separately
PathBuf::from(target) target.clone()
} }
None => { None => {
// If there was no explicit target-dir, then use the last // If there was no explicit target-dir, then use the last