From 1d6c5d14b2d945fc2bb30bb3a99caf6dfa1fd3d9 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Thu, 29 Sep 2022 22:31:02 +0200 Subject: [PATCH] mknod: update to clap 4 --- src/uu/mknod/Cargo.toml | 2 +- src/uu/mknod/src/mknod.rs | 75 ++++++++++++++----------------------- tests/by-util/test_mknod.rs | 6 +-- 3 files changed, 33 insertions(+), 50 deletions(-) diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index f46ace879..7e21983ff 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -16,7 +16,7 @@ name = "uu_mknod" path = "src/mknod.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "^0.2.135" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["mode"] } diff --git a/src/uu/mknod/src/mknod.rs b/src/uu/mknod/src/mknod.rs index cb1d04e33..2a1290d41 100644 --- a/src/uu/mknod/src/mknod.rs +++ b/src/uu/mknod/src/mknod.rs @@ -7,11 +7,10 @@ // spell-checker:ignore (ToDO) parsemode makedev sysmacros perror IFBLK IFCHR IFIFO -use std::ffi::CString; - -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, value_parser, Arg, ArgMatches, Command}; use libc::{dev_t, mode_t}; use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR}; +use std::ffi::CString; use uucore::display::Quotable; use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError}; @@ -51,6 +50,13 @@ fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 { panic!("Unsupported for windows platform") } +#[derive(Clone, PartialEq)] +enum FileType { + Block, + Character, + Fifo, +} + #[cfg(unix)] fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 { let c_str = CString::new(file_name).expect("Failed to convert to CString"); @@ -94,16 +100,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .get_one::("name") .expect("Missing argument 'NAME'"); - // Only check the first character, to allow mnemonic usage like - // 'mknod /dev/rst0 character 18 0'. - let ch = matches - .get_one::("type") - .expect("Missing argument 'TYPE'") - .chars() - .next() - .expect("Failed to get the first char"); + let file_type = matches.get_one::("type").unwrap(); - if ch == 'p' { + if *file_type == FileType::Fifo { if matches.contains_id("major") || matches.contains_id("minor") { Err(UUsageError::new( 1, @@ -116,28 +115,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } else { match ( - matches.get_one::("major"), - matches.get_one::("minor"), + matches.get_one::("major"), + matches.get_one::("minor"), ) { - (None, None) | (_, None) | (None, _) => { + (_, None) | (None, _) => { return Err(UUsageError::new( 1, "Special files require major and minor device numbers.", )); } - (Some(major), Some(minor)) => { - let major = major.parse::().expect("validated by clap"); - let minor = minor.parse::().expect("validated by clap"); - + (Some(&major), Some(&minor)) => { let dev = makedev(major, minor); - let exit_code = if ch == 'b' { - // block special file - _mknod(file_name, S_IFBLK | mode, dev) - } else if ch == 'c' || ch == 'u' { - // char special file - _mknod(file_name, S_IFCHR | mode, dev) - } else { - unreachable!("{} was validated to be only b, c or u", ch); + let exit_code = match file_type { + FileType::Block => _mknod(file_name, S_IFBLK | mode, dev), + FileType::Character => _mknod(file_name, S_IFCHR | mode, dev), + _ => unreachable!("file_type was validated to be only block or character"), }; set_exit_code(exit_code); Ok(()) @@ -146,7 +138,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .override_usage(format_usage(USAGE)) @@ -165,7 +157,6 @@ pub fn uu_app<'a>() -> Command<'a> { .value_name("NAME") .help("name of the new file") .required(true) - .index(1) .value_hint(clap::ValueHint::AnyPath), ) .arg( @@ -173,22 +164,19 @@ pub fn uu_app<'a>() -> Command<'a> { .value_name("TYPE") .help("type of the new file (b, c, u or p)") .required(true) - .validator(valid_type) - .index(2), + .value_parser(parse_type), ) .arg( Arg::new("major") .value_name("MAJOR") .help("major file type") - .validator(valid_u64) - .index(3), + .value_parser(value_parser!(u64)), ) .arg( Arg::new("minor") .value_name("MINOR") .help("minor file type") - .validator(valid_u64) - .index(4), + .value_parser(value_parser!(u64)), ) } @@ -207,21 +195,16 @@ fn get_mode(matches: &ArgMatches) -> Result { } } -fn valid_type(tpe: &str) -> Result<(), String> { +fn parse_type(tpe: &str) -> Result { // Only check the first character, to allow mnemonic usage like // 'mknod /dev/rst0 character 18 0'. tpe.chars() .next() .ok_or_else(|| "missing device type".to_string()) - .and_then(|first_char| { - if vec!['b', 'c', 'u', 'p'].contains(&first_char) { - Ok(()) - } else { - Err(format!("invalid device type {}", tpe.quote())) - } + .and_then(|first_char| match first_char { + 'b' => Ok(FileType::Block), + 'c' | 'u' => Ok(FileType::Character), + 'p' => Ok(FileType::Fifo), + _ => Err(format!("invalid device type {}", tpe.quote())), }) } - -fn valid_u64(num: &str) -> Result<(), String> { - num.parse::().map(|_| ()).map_err(|_| num.into()) -} diff --git a/tests/by-util/test_mknod.rs b/tests/by-util/test_mknod.rs index 15437b9b2..f5bc9fd8a 100644 --- a/tests/by-util/test_mknod.rs +++ b/tests/by-util/test_mknod.rs @@ -13,7 +13,7 @@ fn test_mknod_help() { .arg("--help") .succeeds() .no_stderr() - .stdout_contains("USAGE:"); + .stdout_contains("Usage:"); } #[test] @@ -92,14 +92,14 @@ fn test_mknod_character_device_requires_major_and_minor() { .arg("1") .arg("c") .fails() - .stderr_contains("Invalid value \"c\" for ''"); + .stderr_contains("Invalid value \"c\""); new_ucmd!() .arg("test_file") .arg("c") .arg("c") .arg("1") .fails() - .stderr_contains("Invalid value \"c\" for ''"); + .stderr_contains("Invalid value \"c\""); } #[test]