diff --git a/Cargo.lock b/Cargo.lock index fc4c2739e..f3e8ae4cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,7 +116,7 @@ dependencies = [ "bitflags", "cexpr", "clang-sys", - "clap", + "clap 3.2.22", "env_logger 0.9.0", "lazy_static", "lazycell", @@ -260,22 +260,35 @@ checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", - "clap_lex", + "clap_lex 0.2.4", "indexmap", - "once_cell", "strsim", "termcolor", - "terminal_size", "textwrap", ] [[package]] -name = "clap_complete" -version = "3.2.5" +name = "clap" +version = "4.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" +checksum = "6ea54a38e4bce14ff6931c72e5b3c43da7051df056913d4e7e1fcdb1c03df69d" dependencies = [ - "clap", + "atty", + "bitflags", + "clap_lex 0.3.0", + "once_cell", + "strsim", + "termcolor", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cba7abac9b56dfe2f035098cdb3a43946f276e6db83b72c4e692343f9aab9a" +dependencies = [ + "clap 4.0.14", ] [[package]] @@ -287,6 +300,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "compare" version = "0.1.0" @@ -320,7 +342,7 @@ version = "0.0.16" dependencies = [ "atty", "chrono", - "clap", + "clap 4.0.14", "clap_complete", "conv", "filetime", @@ -2047,7 +2069,7 @@ checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" name = "uu_arch" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "platform-info", "uucore", ] @@ -2056,7 +2078,7 @@ dependencies = [ name = "uu_base32" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2072,7 +2094,7 @@ dependencies = [ name = "uu_basename" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2080,7 +2102,7 @@ dependencies = [ name = "uu_basenc" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uu_base32", "uucore", ] @@ -2090,7 +2112,7 @@ name = "uu_cat" version = "0.0.16" dependencies = [ "atty", - "clap", + "clap 4.0.14", "nix", "thiserror", "uucore", @@ -2100,7 +2122,7 @@ dependencies = [ name = "uu_chcon" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "fts-sys", "libc", "selinux", @@ -2112,7 +2134,7 @@ dependencies = [ name = "uu_chgrp" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2120,7 +2142,7 @@ dependencies = [ name = "uu_chmod" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2129,7 +2151,7 @@ dependencies = [ name = "uu_chown" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2137,7 +2159,7 @@ dependencies = [ name = "uu_chroot" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2145,7 +2167,7 @@ dependencies = [ name = "uu_cksum" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2153,7 +2175,7 @@ dependencies = [ name = "uu_comm" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2161,7 +2183,7 @@ dependencies = [ name = "uu_cp" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "exacl", "filetime", "libc", @@ -2177,7 +2199,7 @@ dependencies = [ name = "uu_csplit" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "regex", "thiserror", "uucore", @@ -2189,7 +2211,7 @@ version = "0.0.16" dependencies = [ "atty", "bstr", - "clap", + "clap 4.0.14", "memchr", "uucore", ] @@ -2199,7 +2221,7 @@ name = "uu_date" version = "0.0.16" dependencies = [ "chrono", - "clap", + "clap 4.0.14", "libc", "uucore", "winapi", @@ -2210,7 +2232,7 @@ name = "uu_dd" version = "0.0.16" dependencies = [ "byte-unit", - "clap", + "clap 4.0.14", "gcd", "libc", "signal-hook", @@ -2221,7 +2243,7 @@ dependencies = [ name = "uu_df" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "unicode-width", "uucore", ] @@ -2230,7 +2252,7 @@ dependencies = [ name = "uu_dir" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "selinux", "uu_ls", "uucore", @@ -2240,7 +2262,7 @@ dependencies = [ name = "uu_dircolors" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "glob", "uucore", ] @@ -2249,7 +2271,7 @@ dependencies = [ name = "uu_dirname" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2258,7 +2280,7 @@ name = "uu_du" version = "0.0.16" dependencies = [ "chrono", - "clap", + "clap 4.0.14", "glob", "uucore", "winapi", @@ -2268,7 +2290,7 @@ dependencies = [ name = "uu_echo" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2276,7 +2298,7 @@ dependencies = [ name = "uu_env" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "nix", "rust-ini", "uucore", @@ -2286,7 +2308,7 @@ dependencies = [ name = "uu_expand" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "unicode-width", "uucore", ] @@ -2295,7 +2317,7 @@ dependencies = [ name = "uu_expr" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "num-bigint", "num-traits", "onig", @@ -2306,7 +2328,7 @@ dependencies = [ name = "uu_factor" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "coz", "num-traits", "paste", @@ -2320,7 +2342,7 @@ dependencies = [ name = "uu_false" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2328,7 +2350,7 @@ dependencies = [ name = "uu_fmt" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "unicode-width", "uucore", ] @@ -2337,7 +2359,7 @@ dependencies = [ name = "uu_fold" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2345,7 +2367,7 @@ dependencies = [ name = "uu_groups" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2355,7 +2377,7 @@ version = "0.0.16" dependencies = [ "blake2b_simd", "blake3", - "clap", + "clap 4.0.14", "digest", "hex", "md-5", @@ -2371,7 +2393,7 @@ dependencies = [ name = "uu_head" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "memchr", "uucore", ] @@ -2380,7 +2402,7 @@ dependencies = [ name = "uu_hostid" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2389,7 +2411,7 @@ dependencies = [ name = "uu_hostname" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "hostname", "uucore", "winapi", @@ -2399,7 +2421,7 @@ dependencies = [ name = "uu_id" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "selinux", "uucore", ] @@ -2408,7 +2430,7 @@ dependencies = [ name = "uu_install" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "file_diff", "filetime", "libc", @@ -2420,7 +2442,7 @@ dependencies = [ name = "uu_join" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "memchr", "uucore", ] @@ -2429,7 +2451,7 @@ dependencies = [ name = "uu_kill" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "nix", "uucore", ] @@ -2438,7 +2460,7 @@ dependencies = [ name = "uu_link" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2446,7 +2468,7 @@ dependencies = [ name = "uu_ln" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2454,7 +2476,7 @@ dependencies = [ name = "uu_logname" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2465,7 +2487,7 @@ version = "0.0.16" dependencies = [ "atty", "chrono", - "clap", + "clap 4.0.14", "glob", "lscolors", "number_prefix", @@ -2481,7 +2503,7 @@ dependencies = [ name = "uu_mkdir" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2489,7 +2511,7 @@ dependencies = [ name = "uu_mkfifo" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2498,7 +2520,7 @@ dependencies = [ name = "uu_mknod" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2507,7 +2529,7 @@ dependencies = [ name = "uu_mktemp" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "rand", "tempfile", "uucore", @@ -2518,7 +2540,7 @@ name = "uu_more" version = "0.0.16" dependencies = [ "atty", - "clap", + "clap 4.0.14", "crossterm", "nix", "unicode-segmentation", @@ -2530,7 +2552,7 @@ dependencies = [ name = "uu_mv" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "fs_extra", "uucore", ] @@ -2539,7 +2561,7 @@ dependencies = [ name = "uu_nice" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "nix", "uucore", @@ -2549,7 +2571,7 @@ dependencies = [ name = "uu_nl" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "regex", "uucore", ] @@ -2559,7 +2581,7 @@ name = "uu_nohup" version = "0.0.16" dependencies = [ "atty", - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2568,7 +2590,7 @@ dependencies = [ name = "uu_nproc" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "num_cpus", "uucore", @@ -2578,7 +2600,7 @@ dependencies = [ name = "uu_numfmt" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2587,7 +2609,7 @@ name = "uu_od" version = "0.0.16" dependencies = [ "byteorder", - "clap", + "clap 4.0.14", "half", "uucore", ] @@ -2596,7 +2618,7 @@ dependencies = [ name = "uu_paste" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2604,7 +2626,7 @@ dependencies = [ name = "uu_pathchk" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2613,7 +2635,7 @@ dependencies = [ name = "uu_pinky" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2621,7 +2643,7 @@ dependencies = [ name = "uu_pr" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "itertools", "quick-error", "regex", @@ -2633,7 +2655,7 @@ dependencies = [ name = "uu_printenv" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2641,7 +2663,7 @@ dependencies = [ name = "uu_printf" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2649,7 +2671,7 @@ dependencies = [ name = "uu_ptx" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "regex", "uucore", ] @@ -2658,7 +2680,7 @@ dependencies = [ name = "uu_pwd" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2666,7 +2688,7 @@ dependencies = [ name = "uu_readlink" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2674,7 +2696,7 @@ dependencies = [ name = "uu_realpath" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2682,7 +2704,7 @@ dependencies = [ name = "uu_relpath" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2690,7 +2712,7 @@ dependencies = [ name = "uu_rm" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "remove_dir_all 0.7.0", "uucore", "walkdir", @@ -2701,7 +2723,7 @@ dependencies = [ name = "uu_rmdir" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", ] @@ -2710,7 +2732,7 @@ dependencies = [ name = "uu_runcon" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "selinux", "thiserror", @@ -2722,7 +2744,7 @@ name = "uu_seq" version = "0.0.16" dependencies = [ "bigdecimal", - "clap", + "clap 4.0.14", "num-bigint", "num-traits", "uucore", @@ -2732,7 +2754,7 @@ dependencies = [ name = "uu_shred" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "rand", "uucore", ] @@ -2741,7 +2763,7 @@ dependencies = [ name = "uu_shuf" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "memchr", "rand", "rand_core", @@ -2752,7 +2774,7 @@ dependencies = [ name = "uu_sleep" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2761,7 +2783,7 @@ name = "uu_sort" version = "0.0.16" dependencies = [ "binary-heap-plus", - "clap", + "clap 4.0.14", "compare", "ctrlc", "fnv", @@ -2779,7 +2801,7 @@ dependencies = [ name = "uu_split" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "memchr", "uucore", ] @@ -2788,7 +2810,7 @@ dependencies = [ name = "uu_stat" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2796,7 +2818,7 @@ dependencies = [ name = "uu_stdbuf" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "tempfile", "uu_stdbuf_libstdbuf", "uucore", @@ -2816,7 +2838,7 @@ dependencies = [ name = "uu_stty" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "nix", "uucore", ] @@ -2825,7 +2847,7 @@ dependencies = [ name = "uu_sum" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2833,7 +2855,7 @@ dependencies = [ name = "uu_sync" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "nix", "uucore", @@ -2844,7 +2866,7 @@ dependencies = [ name = "uu_tac" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "memchr", "memmap2", "regex", @@ -2855,7 +2877,7 @@ dependencies = [ name = "uu_tail" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "memchr", "nix", @@ -2870,7 +2892,7 @@ dependencies = [ name = "uu_tee" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "retain_mut", "uucore", @@ -2880,7 +2902,7 @@ dependencies = [ name = "uu_test" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "redox_syscall", "uucore", @@ -2890,7 +2912,7 @@ dependencies = [ name = "uu_timeout" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "nix", "uucore", @@ -2900,7 +2922,7 @@ dependencies = [ name = "uu_touch" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "filetime", "time", "uucore", @@ -2911,7 +2933,7 @@ dependencies = [ name = "uu_tr" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "nom", "uucore", ] @@ -2920,7 +2942,7 @@ dependencies = [ name = "uu_true" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2928,7 +2950,7 @@ dependencies = [ name = "uu_truncate" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2936,7 +2958,7 @@ dependencies = [ name = "uu_tsort" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2945,7 +2967,7 @@ name = "uu_tty" version = "0.0.16" dependencies = [ "atty", - "clap", + "clap 4.0.14", "nix", "uucore", ] @@ -2954,7 +2976,7 @@ dependencies = [ name = "uu_uname" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "platform-info", "uucore", ] @@ -2963,7 +2985,7 @@ dependencies = [ name = "uu_unexpand" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "unicode-width", "uucore", ] @@ -2972,7 +2994,7 @@ dependencies = [ name = "uu_uniq" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "strum", "strum_macros", "uucore", @@ -2982,7 +3004,7 @@ dependencies = [ name = "uu_unlink" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -2991,7 +3013,7 @@ name = "uu_uptime" version = "0.0.16" dependencies = [ "chrono", - "clap", + "clap 4.0.14", "uucore", ] @@ -2999,7 +3021,7 @@ dependencies = [ name = "uu_users" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -3007,7 +3029,7 @@ dependencies = [ name = "uu_vdir" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "selinux", "uu_ls", "uucore", @@ -3018,7 +3040,7 @@ name = "uu_wc" version = "0.0.16" dependencies = [ "bytecount", - "clap", + "clap 4.0.14", "libc", "nix", "unicode-width", @@ -3030,7 +3052,7 @@ dependencies = [ name = "uu_who" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "uucore", ] @@ -3038,7 +3060,7 @@ dependencies = [ name = "uu_whoami" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "uucore", "winapi", @@ -3048,7 +3070,7 @@ dependencies = [ name = "uu_yes" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "libc", "nix", "uucore", @@ -3058,7 +3080,7 @@ dependencies = [ name = "uucore" version = "0.0.16" dependencies = [ - "clap", + "clap 4.0.14", "data-encoding", "data-encoding-macro", "dns-lookup", diff --git a/Cargo.toml b/Cargo.toml index 6acaf55dc..6086b968e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -261,8 +261,8 @@ uudoc = [ "zip" ] [workspace] [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } -clap_complete = "3.1" +clap = { version = "4.0", features = ["wrap_help", "cargo"] } +clap_complete = "4.0" once_cell = "1.13.1" phf = "0.11.1" selinux = { version="0.3", optional = true } diff --git a/build.rs b/build.rs index c9f07259a..056380f28 100644 --- a/build.rs +++ b/build.rs @@ -39,7 +39,7 @@ pub fn main() { let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap(); mf.write_all( - "type UtilityMap = phf::Map<&'static str, (fn(T) -> i32, fn() -> Command<'static>)>;\n\ + "type UtilityMap = phf::Map<&'static str, (fn(T) -> i32, fn() -> Command)>;\n\ \n\ fn util_map() -> UtilityMap {\n" .as_bytes(), diff --git a/deny.toml b/deny.toml index fc625d0aa..2c8a473c0 100644 --- a/deny.toml +++ b/deny.toml @@ -70,6 +70,10 @@ skip = [ { name = "env_logger", version = "=0.8.4" }, # tempfile { name = "remove_dir_all", version = "=0.5.3" }, + # bindgen (via selinux-sys & fts-sys) + { name = "clap", version = "=3.2.22" }, + # bindgen (via selinux-sys & fts-sys) + { name = "clap_lex", version = "=0.2.4" }, ] # spell-checker: enable diff --git a/out b/out new file mode 100644 index 000000000..e69de29bb diff --git a/src/bin/coreutils.rs b/src/bin/coreutils.rs index c175d9447..74c6f4cdb 100644 --- a/src/bin/coreutils.rs +++ b/src/bin/coreutils.rs @@ -167,7 +167,7 @@ fn gen_completions( process::exit(0); } -fn gen_coreutils_app(util_map: &UtilityMap) -> Command<'static> { +fn gen_coreutils_app(util_map: &UtilityMap) -> Command { let mut command = Command::new("coreutils"); for (_, (_, sub_app)) in util_map { command = command.subcommand(sub_app()); diff --git a/src/bin/uudoc.rs b/src/bin/uudoc.rs index 133cc1751..20b612e00 100644 --- a/src/bin/uudoc.rs +++ b/src/bin/uudoc.rs @@ -110,7 +110,7 @@ fn main() -> io::Result<()> { struct MDWriter<'a, 'b> { w: Box, - command: Command<'a>, + command: Command, name: &'a str, tldr_zip: &'b mut Option>, utils_per_platform: &'b HashMap<&'b str, Vec>, @@ -168,13 +168,16 @@ impl<'a, 'b> MDWriter<'a, 'b> { let mut usage: String = self .command .render_usage() + .to_string() .lines() .skip(1) .map(|l| l.trim()) .filter(|l| !l.is_empty()) .collect::>() .join("\n"); - usage = usage.replace(uucore::execution_phrase(), self.name); + usage = usage + .to_string() + .replace(uucore::execution_phrase(), self.name); writeln!(self.w, "{}", usage)?; writeln!(self.w, "```") } @@ -283,7 +286,10 @@ impl<'a, 'b> MDWriter<'a, 'b> { writeln!( self.w, "
\n\n{}\n\n
", - arg.get_help().unwrap_or_default().replace('\n', "
") + arg.get_help() + .unwrap_or_default() + .to_string() + .replace('\n', "
") )?; } writeln!(self.w, "\n") diff --git a/src/uu/arch/Cargo.toml b/src/uu/arch/Cargo.toml index 6231fa87c..ef4964b66 100644 --- a/src/uu/arch/Cargo.toml +++ b/src/uu/arch/Cargo.toml @@ -16,7 +16,7 @@ path = "src/arch.rs" [dependencies] platform-info = "1.0.0" -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/arch/src/arch.rs b/src/uu/arch/src/arch.rs index 69049868d..62a07159e 100644 --- a/src/uu/arch/src/arch.rs +++ b/src/uu/arch/src/arch.rs @@ -23,7 +23,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) diff --git a/src/uu/base32/Cargo.toml b/src/uu/base32/Cargo.toml index bb72325bb..a996fa811 100644 --- a/src/uu/base32/Cargo.toml +++ b/src/uu/base32/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/base32.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features = ["encoding"] } [[bin]] diff --git a/src/uu/base32/src/base32.rs b/src/uu/base32/src/base32.rs index 2165e0dcc..01932e675 100644 --- a/src/uu/base32/src/base32.rs +++ b/src/uu/base32/src/base32.rs @@ -35,6 +35,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { ) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { base_common::base_app(ABOUT, USAGE) } diff --git a/src/uu/base32/src/base_common.rs b/src/uu/base32/src/base_common.rs index 6cceb50f4..f68aa6b86 100644 --- a/src/uu/base32/src/base_common.rs +++ b/src/uu/base32/src/base_common.rs @@ -18,7 +18,7 @@ use std::fs::File; use std::io::{BufReader, Stdin}; use std::path::Path; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; pub static BASE_CMD_PARSE_ERROR: i32 = 1; @@ -77,21 +77,25 @@ impl Config { .transpose()?; Ok(Self { - decode: options.contains_id(options::DECODE), - ignore_garbage: options.contains_id(options::IGNORE_GARBAGE), + decode: options.get_flag(options::DECODE), + ignore_garbage: options.get_flag(options::IGNORE_GARBAGE), wrap_cols: cols, to_read: file, }) } } -pub fn parse_base_cmd_args(args: impl uucore::Args, about: &str, usage: &str) -> UResult { +pub fn parse_base_cmd_args( + args: impl uucore::Args, + about: &'static str, + usage: &str, +) -> UResult { let command = base_app(about, usage); let arg_list = args.collect_lossy(); Config::from(&command.try_get_matches_from(arg_list)?) } -pub fn base_app<'a>(about: &'a str, usage: &'a str) -> Command<'a> { +pub fn base_app(about: &'static str, usage: &str) -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(about) @@ -102,19 +106,21 @@ pub fn base_app<'a>(about: &'a str, usage: &'a str) -> Command<'a> { Arg::new(options::DECODE) .short('d') .long(options::DECODE) - .help("decode data"), + .help("decode data") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::IGNORE_GARBAGE) .short('i') .long(options::IGNORE_GARBAGE) - .help("when decoding, ignore non-alphabetic characters"), + .help("when decoding, ignore non-alphabetic characters") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::WRAP) .short('w') .long(options::WRAP) - .takes_value(true) + .value_name("COLS") .help( "wrap encoded lines after COLS character (default 76, 0 to disable wrapping)", ), @@ -124,7 +130,7 @@ pub fn base_app<'a>(about: &'a str, usage: &'a str) -> Command<'a> { .arg( Arg::new(options::FILE) .index(1) - .multiple_occurrences(true) + .action(clap::ArgAction::Append) .value_hint(clap::ValueHint::FilePath), ) } diff --git a/src/uu/basename/Cargo.toml b/src/uu/basename/Cargo.toml index b7496c317..125191dd2 100644 --- a/src/uu/basename/Cargo.toml +++ b/src/uu/basename/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/basename.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/basename/src/basename.rs b/src/uu/basename/src/basename.rs index 5a68552d5..65744e698 100644 --- a/src/uu/basename/src/basename.rs +++ b/src/uu/basename/src/basename.rs @@ -7,7 +7,7 @@ // spell-checker:ignore (ToDO) fullname -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::path::{is_separator, PathBuf}; use uucore::display::Quotable; use uucore::error::{UResult, UUsageError}; @@ -56,9 +56,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { return Err(UUsageError::new(1, "missing operand".to_string())); } - let opt_suffix = matches.contains_id(options::SUFFIX); - let opt_multiple = matches.contains_id(options::MULTIPLE); - let opt_zero = matches.contains_id(options::ZERO); + let opt_suffix = matches.get_one::(options::SUFFIX).is_some(); + let opt_multiple = matches.get_flag(options::MULTIPLE); + let opt_zero = matches.get_flag(options::ZERO); let multiple_paths = opt_suffix || opt_multiple; let name_args_count = matches .get_many::(options::NAME) @@ -115,7 +115,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -125,11 +125,12 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::MULTIPLE) .short('a') .long(options::MULTIPLE) - .help("support multiple arguments and treat each as a NAME"), + .help("support multiple arguments and treat each as a NAME") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NAME) - .multiple_occurrences(true) + .action(clap::ArgAction::Append) .value_hint(clap::ValueHint::AnyPath) .hide(true), ) @@ -144,7 +145,8 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::ZERO) .short('z') .long(options::ZERO) - .help("end each output line with NUL, not newline"), + .help("end each output line with NUL, not newline") + .action(ArgAction::SetTrue), ) } diff --git a/src/uu/basenc/Cargo.toml b/src/uu/basenc/Cargo.toml index 713d84e76..ac22c84b7 100644 --- a/src/uu/basenc/Cargo.toml +++ b/src/uu/basenc/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/basenc.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features = ["encoding"] } uu_base32 = { version=">=0.0.16", package="uu_base32", path="../base32"} diff --git a/src/uu/basenc/src/basenc.rs b/src/uu/basenc/src/basenc.rs index d884c04e3..cb9e38879 100644 --- a/src/uu/basenc/src/basenc.rs +++ b/src/uu/basenc/src/basenc.rs @@ -8,7 +8,7 @@ //spell-checker:ignore (args) lsbf msbf -use clap::{Arg, Command}; +use clap::{Arg, ArgAction, Command}; use uu_base32::base_common::{self, Config, BASE_CMD_PARSE_ERROR}; use uucore::{ @@ -41,10 +41,14 @@ const ENCODINGS: &[(&str, Format)] = &[ const USAGE: &str = "{} [OPTION]... [FILE]"; -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { let mut command = base_common::base_app(ABOUT, USAGE); for encoding in ENCODINGS { - command = command.arg(Arg::new(encoding.0).long(encoding.0)); + command = command.arg( + Arg::new(encoding.0) + .long(encoding.0) + .action(ArgAction::SetTrue), + ); } command } @@ -55,7 +59,7 @@ fn parse_cmd_args(args: impl uucore::Args) -> UResult<(Config, Format)> { .with_exit_code(1)?; let format = ENCODINGS .iter() - .find(|encoding| matches.contains_id(encoding.0)) + .find(|encoding| matches.get_flag(encoding.0)) .ok_or_else(|| UUsageError::new(BASE_CMD_PARSE_ERROR, "missing encoding type"))? .1; let config = Config::from(&matches)?; diff --git a/src/uu/cat/Cargo.toml b/src/uu/cat/Cargo.toml index 0b1698f78..10748c4b2 100644 --- a/src/uu/cat/Cargo.toml +++ b/src/uu/cat/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/cat.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } thiserror = "1.0" atty = "0.2" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "pipes"] } diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index f6291d8ae..3200bdf4e 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -11,7 +11,7 @@ // spell-checker:ignore (ToDO) nonprint nonblank nonprinting // last synced with: cat (GNU coreutils) 8.13 -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::fs::{metadata, File}; use std::io::{self, Read, Write}; use thiserror::Error; @@ -185,9 +185,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; - let number_mode = if matches.contains_id(options::NUMBER_NONBLANK) { + let number_mode = if matches.get_flag(options::NUMBER_NONBLANK) { NumberingMode::NonEmpty - } else if matches.contains_id(options::NUMBER) { + } else if matches.get_flag(options::NUMBER) { NumberingMode::All } else { NumberingMode::None @@ -200,7 +200,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { options::SHOW_NONPRINTING.to_owned(), ] .iter() - .any(|v| matches.contains_id(v)); + .any(|v| matches.get_flag(v)); let show_ends = vec![ options::SHOW_ENDS.to_owned(), @@ -208,7 +208,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { options::SHOW_NONPRINTING_ENDS.to_owned(), ] .iter() - .any(|v| matches.contains_id(v)); + .any(|v| matches.get_flag(v)); let show_tabs = vec![ options::SHOW_ALL.to_owned(), @@ -216,9 +216,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { options::SHOW_NONPRINTING_TABS.to_owned(), ] .iter() - .any(|v| matches.contains_id(v)); + .any(|v| matches.get_flag(v)); - let squeeze_blank = matches.contains_id(options::SQUEEZE_BLANK); + let squeeze_blank = matches.get_flag(options::SQUEEZE_BLANK); let files: Vec = match matches.get_many::(options::FILE) { Some(v) => v.clone().map(|v| v.to_owned()).collect(), None => vec!["-".to_owned()], @@ -234,7 +234,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { cat_files(&files, &options) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .name(NAME) .version(crate_version!()) @@ -244,62 +244,71 @@ pub fn uu_app<'a>() -> Command<'a> { .arg( Arg::new(options::FILE) .hide(true) - .multiple_occurrences(true) + .action(clap::ArgAction::Append) .value_hint(clap::ValueHint::FilePath), ) .arg( Arg::new(options::SHOW_ALL) .short('A') .long(options::SHOW_ALL) - .help("equivalent to -vET"), + .help("equivalent to -vET") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NUMBER_NONBLANK) .short('b') .long(options::NUMBER_NONBLANK) .help("number nonempty output lines, overrides -n") - .overrides_with(options::NUMBER), + .overrides_with(options::NUMBER) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SHOW_NONPRINTING_ENDS) .short('e') - .help("equivalent to -vE"), + .help("equivalent to -vE") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SHOW_ENDS) .short('E') .long(options::SHOW_ENDS) - .help("display $ at end of each line"), + .help("display $ at end of each line") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NUMBER) .short('n') .long(options::NUMBER) - .help("number all output lines"), + .help("number all output lines") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SQUEEZE_BLANK) .short('s') .long(options::SQUEEZE_BLANK) - .help("suppress repeated empty output lines"), + .help("suppress repeated empty output lines") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SHOW_NONPRINTING_TABS) .short('t') .long(options::SHOW_NONPRINTING_TABS) - .help("equivalent to -vT"), + .help("equivalent to -vT") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SHOW_TABS) .short('T') .long(options::SHOW_TABS) - .help("display TAB characters at ^I"), + .help("display TAB characters at ^I") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SHOW_NONPRINTING) .short('v') .long(options::SHOW_NONPRINTING) - .help("use ^ and M- notation, except for LF (\\n) and TAB (\\t)"), + .help("use ^ and M- notation, except for LF (\\n) and TAB (\\t)") + .action(ArgAction::SetTrue), ) } diff --git a/src/uu/chcon/Cargo.toml b/src/uu/chcon/Cargo.toml index 1f3b5e299..ea39f4ca5 100644 --- a/src/uu/chcon/Cargo.toml +++ b/src/uu/chcon/Cargo.toml @@ -14,7 +14,7 @@ edition = "2021" path = "src/chcon.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version = ">=0.0.9", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } selinux = { version = "0.3" } fts-sys = { version = "0.2" } diff --git a/src/uu/chcon/src/chcon.rs b/src/uu/chcon/src/chcon.rs index e80293f4d..1742ca1a2 100644 --- a/src/uu/chcon/src/chcon.rs +++ b/src/uu/chcon/src/chcon.rs @@ -7,7 +7,7 @@ use uucore::error::{UResult, USimpleError, UUsageError}; use uucore::format_usage; use uucore::{display::Quotable, show_error, show_warning}; -use clap::{Arg, Command}; +use clap::{Arg, ArgAction, Command}; use selinux::{OpaqueSecurityContext, SecurityContext}; use std::borrow::Cow; @@ -66,14 +66,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let options = match parse_command_line(config, args) { Ok(r) => r, Err(r) => { - if let Error::CommandLine(r) = &r { - match r.kind() { - clap::ErrorKind::DisplayHelp | clap::ErrorKind::DisplayVersion => { - println!("{}", r); - return Ok(()); - } - _ => {} - } + if let Error::CommandLine(r) = r { + return Err(r.into()); } return Err(UUsageError::new(libc::EXIT_FAILURE, format!("{}.\n", r))); @@ -106,7 +100,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } CommandLineMode::ContextBased { context } => { - let c_context = match os_str_to_c_string(context) { + let c_context = match os_str_to_c_string(&context) { Ok(context) => context, Err(_r) => { @@ -156,16 +150,18 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Err(libc::EXIT_FAILURE.into()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(VERSION) .about(ABOUT) .override_usage(format_usage(USAGE)) .infer_long_args(true) + .disable_help_flag(true) .arg( Arg::new(options::HELP) .long(options::HELP) - .help("Print help information."), + .help("Print help information.") + .action(ArgAction::Help), ) .arg( Arg::new(options::dereference::DEREFERENCE) @@ -174,29 +170,32 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Affect the referent of each symbolic link (this is the default), \ rather than the symbolic link itself.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::dereference::NO_DEREFERENCE) .short('h') .long(options::dereference::NO_DEREFERENCE) - .help("Affect symbolic links instead of any referenced file."), + .help("Affect symbolic links instead of any referenced file.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::preserve_root::PRESERVE_ROOT) .long(options::preserve_root::PRESERVE_ROOT) .conflicts_with(options::preserve_root::NO_PRESERVE_ROOT) - .help("Fail to operate recursively on '/'."), + .help("Fail to operate recursively on '/'.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::preserve_root::NO_PRESERVE_ROOT) .long(options::preserve_root::NO_PRESERVE_ROOT) - .help("Do not treat '/' specially (the default)."), + .help("Do not treat '/' specially (the default).") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::REFERENCE) .long(options::REFERENCE) - .takes_value(true) .value_name("RFILE") .value_hint(clap::ValueHint::FilePath) .conflicts_with_all(&[options::USER, options::ROLE, options::TYPE, options::RANGE]) @@ -210,7 +209,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::USER) .short('u') .long(options::USER) - .takes_value(true) .value_name("USER") .value_hint(clap::ValueHint::Username) .help("Set user USER in the target security context.") @@ -220,7 +218,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::ROLE) .short('r') .long(options::ROLE) - .takes_value(true) .value_name("ROLE") .help("Set role ROLE in the target security context.") .value_parser(ValueParser::os_string()), @@ -229,7 +226,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::TYPE) .short('t') .long(options::TYPE) - .takes_value(true) .value_name("TYPE") .help("Set type TYPE in the target security context.") .value_parser(ValueParser::os_string()), @@ -238,7 +234,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::RANGE) .short('l') .long(options::RANGE) - .takes_value(true) .value_name("RANGE") .help("Set range RANGE in the target security context.") .value_parser(ValueParser::os_string()), @@ -247,7 +242,8 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::RECURSIVE) .short('R') .long(options::RECURSIVE) - .help("Operate on files and directories recursively."), + .help("Operate on files and directories recursively.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK) @@ -260,7 +256,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "If a command line argument is a symbolic link to a directory, \ traverse it. Only valid when -R is specified.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::sym_links::FOLLOW_DIR_SYM_LINKS) @@ -273,7 +270,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Traverse every symbolic link to a directory encountered. \ Only valid when -R is specified.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::sym_links::NO_FOLLOW_SYM_LINKS) @@ -286,19 +284,21 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Do not traverse any symbolic links (default). \ Only valid when -R is specified.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::VERBOSE) .short('v') .long(options::VERBOSE) - .help("Output a diagnostic for every file processed."), + .help("Output a diagnostic for every file processed.") + .action(ArgAction::SetTrue), ) .arg( Arg::new("FILE") - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::FilePath) - .min_values(1) + .num_args(1..) .value_parser(ValueParser::os_string()), ) } @@ -316,11 +316,11 @@ struct Options { fn parse_command_line(config: clap::Command, args: impl uucore::Args) -> Result { let matches = config.try_get_matches_from(args)?; - let verbose = matches.contains_id(options::VERBOSE); + let verbose = matches.get_flag(options::VERBOSE); - let (recursive_mode, affect_symlink_referent) = if matches.contains_id(options::RECURSIVE) { - if matches.contains_id(options::sym_links::FOLLOW_DIR_SYM_LINKS) { - if matches.contains_id(options::dereference::NO_DEREFERENCE) { + let (recursive_mode, affect_symlink_referent) = if matches.get_flag(options::RECURSIVE) { + if matches.get_flag(options::sym_links::FOLLOW_DIR_SYM_LINKS) { + if matches.get_flag(options::dereference::NO_DEREFERENCE) { return Err(Error::ArgumentsMismatch(format!( "'--{}' with '--{}' require '-P'", options::RECURSIVE, @@ -329,8 +329,8 @@ fn parse_command_line(config: clap::Command, args: impl uucore::Args) -> Result< } (RecursiveMode::RecursiveAndFollowAllDirSymLinks, true) - } else if matches.contains_id(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK) { - if matches.contains_id(options::dereference::NO_DEREFERENCE) { + } else if matches.get_flag(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK) { + if matches.get_flag(options::dereference::NO_DEREFERENCE) { return Err(Error::ArgumentsMismatch(format!( "'--{}' with '--{}' require '-P'", options::RECURSIVE, @@ -340,7 +340,7 @@ fn parse_command_line(config: clap::Command, args: impl uucore::Args) -> Result< (RecursiveMode::RecursiveAndFollowArgDirSymLinks, true) } else { - if matches.contains_id(options::dereference::DEREFERENCE) { + if matches.get_flag(options::dereference::DEREFERENCE) { return Err(Error::ArgumentsMismatch(format!( "'--{}' with '--{}' require either '-H' or '-L'", options::RECURSIVE, @@ -351,12 +351,12 @@ fn parse_command_line(config: clap::Command, args: impl uucore::Args) -> Result< (RecursiveMode::RecursiveButDoNotFollowSymLinks, false) } } else { - let no_dereference = matches.contains_id(options::dereference::NO_DEREFERENCE); + let no_dereference = matches.get_flag(options::dereference::NO_DEREFERENCE); (RecursiveMode::NotRecursive, !no_dereference) }; // By default, do not preserve root. - let preserve_root = matches.contains_id(options::preserve_root::PRESERVE_ROOT); + let preserve_root = matches.get_flag(options::preserve_root::PRESERVE_ROOT); let mut files = matches.get_many::("FILE").unwrap_or_default(); diff --git a/src/uu/chgrp/Cargo.toml b/src/uu/chgrp/Cargo.toml index da98068ca..94fb874ba 100644 --- a/src/uu/chgrp/Cargo.toml +++ b/src/uu/chgrp/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/chgrp.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } [[bin]] diff --git a/src/uu/chgrp/src/chgrp.rs b/src/uu/chgrp/src/chgrp.rs index 0c431c235..a97f6f1ef 100644 --- a/src/uu/chgrp/src/chgrp.rs +++ b/src/uu/chgrp/src/chgrp.rs @@ -13,7 +13,7 @@ use uucore::error::{FromIo, UResult, USimpleError}; use uucore::format_usage; use uucore::perms::{chown_base, options, IfFrom}; -use clap::{Arg, ArgMatches, Command}; +use clap::{Arg, ArgAction, ArgMatches, Command}; use std::fs; use std::os::unix::fs::MetadataExt; @@ -57,42 +57,49 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { chown_base(uu_app(), args, options::ARG_GROUP, parse_gid_and_uid, true) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(VERSION) .about(ABOUT) .override_usage(format_usage(USAGE)) .infer_long_args(true) + .disable_help_flag(true) .arg( Arg::new(options::HELP) .long(options::HELP) .help("Print help information.") + .action(ArgAction::Help) ) .arg( Arg::new(options::verbosity::CHANGES) .short('c') .long(options::verbosity::CHANGES) - .help("like verbose but report only when a change is made"), + .help("like verbose but report only when a change is made") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::verbosity::SILENT) .short('f') - .long(options::verbosity::SILENT), + .long(options::verbosity::SILENT) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::verbosity::QUIET) .long(options::verbosity::QUIET) - .help("suppress most error messages"), + .help("suppress most error messages") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::verbosity::VERBOSE) .short('v') .long(options::verbosity::VERBOSE) - .help("output a diagnostic for every file processed"), + .help("output a diagnostic for every file processed") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::dereference::DEREFERENCE) - .long(options::dereference::DEREFERENCE), + .long(options::dereference::DEREFERENCE) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::dereference::NO_DEREFERENCE) @@ -100,47 +107,52 @@ pub fn uu_app<'a>() -> Command<'a> { .long(options::dereference::NO_DEREFERENCE) .help( "affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::preserve_root::PRESERVE) .long(options::preserve_root::PRESERVE) - .help("fail to operate recursively on '/'"), + .help("fail to operate recursively on '/'") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::preserve_root::NO_PRESERVE) .long(options::preserve_root::NO_PRESERVE) - .help("do not treat '/' specially (the default)"), + .help("do not treat '/' specially (the default)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::REFERENCE) .long(options::REFERENCE) .value_name("RFILE") .value_hint(clap::ValueHint::FilePath) - .help("use RFILE's group rather than specifying GROUP values") - .takes_value(true) - .multiple_occurrences(false), + .help("use RFILE's group rather than specifying GROUP values"), ) .arg( Arg::new(options::RECURSIVE) .short('R') .long(options::RECURSIVE) - .help("operate on files and directories recursively"), + .help("operate on files and directories recursively") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::TRAVERSE) .short(options::traverse::TRAVERSE.chars().next().unwrap()) - .help("if a command line argument is a symbolic link to a directory, traverse it"), + .help("if a command line argument is a symbolic link to a directory, traverse it") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::NO_TRAVERSE) .short(options::traverse::NO_TRAVERSE.chars().next().unwrap()) .help("do not traverse any symbolic links (default)") - .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]), + .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::EVERY) .short(options::traverse::EVERY.chars().next().unwrap()) - .help("traverse every symbolic link to a directory encountered"), + .help("traverse every symbolic link to a directory encountered") + .action(ArgAction::SetTrue), ) } diff --git a/src/uu/chmod/Cargo.toml b/src/uu/chmod/Cargo.toml index 0b96576f7..c794ad821 100644 --- a/src/uu/chmod/Cargo.toml +++ b/src/uu/chmod/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/chmod.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=["fs", "mode"] } diff --git a/src/uu/chmod/src/chmod.rs b/src/uu/chmod/src/chmod.rs index b88b22a05..c21705ccd 100644 --- a/src/uu/chmod/src/chmod.rs +++ b/src/uu/chmod/src/chmod.rs @@ -7,7 +7,7 @@ // spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::fs; use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::path::Path; @@ -39,8 +39,8 @@ const USAGE: &str = "\ {} [OPTION]... OCTAL-MODE FILE... {} [OPTION]... --reference=RFILE FILE..."; -fn get_long_usage() -> String { - String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.") +fn get_long_usage() -> &'static str { + "Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'." } #[uucore::main] @@ -53,15 +53,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let after_help = get_long_usage(); - let matches = uu_app() - .after_help(&after_help[..]) - .try_get_matches_from(args)?; + let matches = uu_app().after_help(after_help).try_get_matches_from(args)?; - let changes = matches.contains_id(options::CHANGES); - let quiet = matches.contains_id(options::QUIET); - let verbose = matches.contains_id(options::VERBOSE); - let preserve_root = matches.contains_id(options::PRESERVE_ROOT); - let recursive = matches.contains_id(options::RECURSIVE); + let changes = matches.get_flag(options::CHANGES); + let quiet = matches.get_flag(options::QUIET); + let verbose = matches.get_flag(options::VERBOSE); + let preserve_root = matches.get_flag(options::PRESERVE_ROOT); + let recursive = matches.get_flag(options::RECURSIVE); let fmode = match matches.get_one::(options::REFERENCE) { Some(fref) => match fs::metadata(fref) { Ok(meta) => Some(meta.mode()), @@ -112,7 +110,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { chmoder.chmod(&files) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -122,56 +120,58 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::CHANGES) .long(options::CHANGES) .short('c') - .help("like verbose but report only when a change is made"), + .help("like verbose but report only when a change is made") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::QUIET) .long(options::QUIET) .visible_alias("silent") .short('f') - .help("suppress most error messages"), + .help("suppress most error messages") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::VERBOSE) .long(options::VERBOSE) .short('v') - .help("output a diagnostic for every file processed"), + .help("output a diagnostic for every file processed") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_PRESERVE_ROOT) .long(options::NO_PRESERVE_ROOT) - .help("do not treat '/' specially (the default)"), + .help("do not treat '/' specially (the default)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::PRESERVE_ROOT) .long(options::PRESERVE_ROOT) - .help("fail to operate recursively on '/'"), + .help("fail to operate recursively on '/'") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::RECURSIVE) .long(options::RECURSIVE) .short('R') - .help("change files and directories recursively"), + .help("change files and directories recursively") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::REFERENCE) .long("reference") - .takes_value(true) .value_hint(clap::ValueHint::FilePath) .help("use RFILE's mode instead of MODE values"), ) .arg( - Arg::new(options::MODE) - .required_unless_present(options::REFERENCE) - .takes_value(true), - // It would be nice if clap could parse with delimiter, e.g. "g-x,u+x", - // however .multiple_occurrences(true) cannot be used here because FILE already needs that. - // Only one positional argument with .multiple_occurrences(true) set is allowed per command + Arg::new(options::MODE).required_unless_present(options::REFERENCE), // It would be nice if clap could parse with delimiter, e.g. "g-x,u+x", + // however .multiple_occurrences(true) cannot be used here because FILE already needs that. + // Only one positional argument with .multiple_occurrences(true) set is allowed per command ) .arg( Arg::new(options::FILE) .required_unless_present(options::MODE) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath), ) } diff --git a/src/uu/chown/Cargo.toml b/src/uu/chown/Cargo.toml index 736a0328d..cb425e819 100644 --- a/src/uu/chown/Cargo.toml +++ b/src/uu/chown/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/chown.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } [[bin]] diff --git a/src/uu/chown/src/chown.rs b/src/uu/chown/src/chown.rs index 2aefb4879..d99516d92 100644 --- a/src/uu/chown/src/chown.rs +++ b/src/uu/chown/src/chown.rs @@ -14,7 +14,7 @@ use uucore::perms::{chown_base, options, IfFrom}; use uucore::error::{FromIo, UResult, USimpleError}; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use std::fs; use std::os::unix::fs::MetadataExt; @@ -63,22 +63,25 @@ 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!()) .about(ABOUT) .override_usage(format_usage(USAGE)) .infer_long_args(true) + .disable_help_flag(true) .arg( Arg::new(options::HELP) .long(options::HELP) - .help("Print help information."), + .help("Print help information.") + .action(ArgAction::Help), ) .arg( Arg::new(options::verbosity::CHANGES) .short('c') .long(options::verbosity::CHANGES) - .help("like verbose but report only when a change is made"), + .help("like verbose but report only when a change is made") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::dereference::DEREFERENCE) @@ -86,7 +89,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "affect the referent of each symbolic link (this is the default), \ rather than the symbolic link itself", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::dereference::NO_DEREFERENCE) @@ -95,7 +99,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "affect symbolic links instead of any referenced file \ (useful only on systems that can change the ownership of a symlink)", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::FROM) @@ -111,23 +116,27 @@ pub fn uu_app<'a>() -> Command<'a> { .arg( Arg::new(options::preserve_root::PRESERVE) .long(options::preserve_root::PRESERVE) - .help("fail to operate recursively on '/'"), + .help("fail to operate recursively on '/'") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::preserve_root::NO_PRESERVE) .long(options::preserve_root::NO_PRESERVE) - .help("do not treat '/' specially (the default)"), + .help("do not treat '/' specially (the default)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::verbosity::QUIET) .long(options::verbosity::QUIET) - .help("suppress most error messages"), + .help("suppress most error messages") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::RECURSIVE) .short('R') .long(options::RECURSIVE) - .help("operate on files and directories recursively"), + .help("operate on files and directories recursively") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::REFERENCE) @@ -135,36 +144,41 @@ pub fn uu_app<'a>() -> Command<'a> { .help("use RFILE's owner and group rather than specifying OWNER:GROUP values") .value_name("RFILE") .value_hint(clap::ValueHint::FilePath) - .min_values(1), + .num_args(1..), ) .arg( Arg::new(options::verbosity::SILENT) .short('f') - .long(options::verbosity::SILENT), + .long(options::verbosity::SILENT) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::TRAVERSE) .short(options::traverse::TRAVERSE.chars().next().unwrap()) .help("if a command line argument is a symbolic link to a directory, traverse it") - .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]), + .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::EVERY) .short(options::traverse::EVERY.chars().next().unwrap()) .help("traverse every symbolic link to a directory encountered") - .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]), + .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::NO_TRAVERSE) .short(options::traverse::NO_TRAVERSE.chars().next().unwrap()) .help("do not traverse any symbolic links (default)") - .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]), + .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::verbosity::VERBOSE) .long(options::verbosity::VERBOSE) .short('v') - .help("output a diagnostic for every file processed"), + .help("output a diagnostic for every file processed") + .action(ArgAction::SetTrue), ) } diff --git a/src/uu/chroot/Cargo.toml b/src/uu/chroot/Cargo.toml index 9475b775e..a021d207a 100644 --- a/src/uu/chroot/Cargo.toml +++ b/src/uu/chroot/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/chroot.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } [[bin]] diff --git a/src/uu/chroot/src/chroot.rs b/src/uu/chroot/src/chroot.rs index 1414da666..c80b4ab87 100644 --- a/src/uu/chroot/src/chroot.rs +++ b/src/uu/chroot/src/chroot.rs @@ -10,7 +10,7 @@ mod error; use crate::error::ChrootError; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::ffi::CString; use std::io::Error; use std::os::unix::prelude::OsStrExt; @@ -49,7 +49,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { None => return Err(ChrootError::MissingNewRoot.into()), }; - let skip_chdir = matches.contains_id(options::SKIP_CHDIR); + let skip_chdir = matches.get_flag(options::SKIP_CHDIR); // We are resolving the path in case it is a symlink or /. or /../ if skip_chdir && canonicalize(newroot, MissingHandling::Normal, ResolveMode::Logical) @@ -116,7 +116,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -168,13 +168,14 @@ pub fn uu_app<'a>() -> Command<'a> { "Use this option to not change the working directory \ to / after changing the root directory to newroot, \ i.e., inside the chroot.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::COMMAND) + .action(ArgAction::Append) .value_hint(clap::ValueHint::CommandName) .hide(true) - .multiple_occurrences(true) .index(2), ) } diff --git a/src/uu/cksum/Cargo.toml b/src/uu/cksum/Cargo.toml index 9075b9592..98bd60c5a 100644 --- a/src/uu/cksum/Cargo.toml +++ b/src/uu/cksum/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/cksum.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index 8008833ad..448f40ac4 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -137,7 +137,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .name(NAME) .version(crate_version!()) @@ -147,7 +147,7 @@ pub fn uu_app<'a>() -> Command<'a> { .arg( Arg::new(options::FILE) .hide(true) - .multiple_occurrences(true) + .action(clap::ArgAction::Append) .value_hint(clap::ValueHint::FilePath), ) } diff --git a/src/uu/comm/Cargo.toml b/src/uu/comm/Cargo.toml index 12f22ecf4..ff59b88a3 100644 --- a/src/uu/comm/Cargo.toml +++ b/src/uu/comm/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/comm.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/comm/src/comm.rs b/src/uu/comm/src/comm.rs index fe6236efe..a3b4bbde2 100644 --- a/src/uu/comm/src/comm.rs +++ b/src/uu/comm/src/comm.rs @@ -15,7 +15,7 @@ use uucore::error::FromIo; use uucore::error::UResult; use uucore::format_usage; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; static ABOUT: &str = "compare two sorted files line by line"; static LONG_HELP: &str = ""; @@ -38,10 +38,10 @@ fn mkdelim(col: usize, opts: &ArgMatches) -> String { delim => delim, }; - if col > 1 && !opts.contains_id(options::COLUMN_1) { + if col > 1 && !opts.get_flag(options::COLUMN_1) { s.push_str(delim.as_ref()); } - if col > 2 && !opts.contains_id(options::COLUMN_2) { + if col > 2 && !opts.get_flag(options::COLUMN_2) { s.push_str(delim.as_ref()); } @@ -91,7 +91,7 @@ fn comm(a: &mut LineReader, b: &mut LineReader, opts: &ArgMatches) { match ord { Ordering::Less => { - if !opts.contains_id(options::COLUMN_1) { + if !opts.get_flag(options::COLUMN_1) { ensure_nl(ra); print!("{}{}", delim[1], ra); } @@ -99,7 +99,7 @@ fn comm(a: &mut LineReader, b: &mut LineReader, opts: &ArgMatches) { na = a.read_line(ra); } Ordering::Greater => { - if !opts.contains_id(options::COLUMN_2) { + if !opts.get_flag(options::COLUMN_2) { ensure_nl(rb); print!("{}{}", delim[2], rb); } @@ -107,7 +107,7 @@ fn comm(a: &mut LineReader, b: &mut LineReader, opts: &ArgMatches) { nb = b.read_line(rb); } Ordering::Equal => { - if !opts.contains_id(options::COLUMN_3) { + if !opts.get_flag(options::COLUMN_3) { ensure_nl(ra); print!("{}{}", delim[3], ra); } @@ -144,7 +144,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -154,17 +154,20 @@ pub fn uu_app<'a>() -> Command<'a> { .arg( Arg::new(options::COLUMN_1) .short('1') - .help("suppress column 1 (lines unique to FILE1)"), + .help("suppress column 1 (lines unique to FILE1)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::COLUMN_2) .short('2') - .help("suppress column 2 (lines unique to FILE2)"), + .help("suppress column 2 (lines unique to FILE2)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::COLUMN_3) .short('3') - .help("suppress column 3 (lines that appear in both files)"), + .help("suppress column 3 (lines that appear in both files)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DELIMITER) diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index 025c168d3..2c71b725f 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -19,7 +19,7 @@ edition = "2021" path = "src/cp.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } filetime = "0.2" libc = "0.2.135" quick-error = "2.0.1" diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 16d498744..8b9226c1a 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -31,7 +31,7 @@ use std::path::{Path, PathBuf, StripPrefixError}; use std::str::FromStr; use std::string::ToString; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use filetime::FileTime; #[cfg(unix)] use libc::mkfifo; @@ -92,6 +92,8 @@ quick_error! { /// Invalid arguments to backup Backup(description: String) { display("{}\nTry '{} --help' for more information.", description, uucore::execution_phrase()) } + + NotADirectory(path: String) { display("'{}' is not a directory", path) } } } @@ -224,7 +226,6 @@ pub struct Options { } static ABOUT: &str = "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY."; -static LONG_HELP: &str = ""; static EXIT_ERR: i32 = 1; const USAGE: &str = "\ @@ -255,7 +256,6 @@ mod options { pub const PRESERVE: &str = "preserve"; pub const PRESERVE_DEFAULT_ATTRIBUTES: &str = "preserve-default-attributes"; pub const RECURSIVE: &str = "recursive"; - pub const RECURSIVE_ALIAS: &str = "recursive_alias"; pub const REFLINK: &str = "reflink"; pub const REMOVE_DESTINATION: &str = "remove-destination"; pub const SPARSE: &str = "sparse"; @@ -289,7 +289,7 @@ static DEFAULT_ATTRIBUTES: &[Attribute] = &[ Attribute::Timestamps, ]; -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { const MODE_ARGS: &[&str] = &[ options::LINK, options::REFLINK, @@ -309,13 +309,6 @@ pub fn uu_app<'a>() -> Command<'a> { .long(options::TARGET_DIRECTORY) .value_name(options::TARGET_DIRECTORY) .value_hint(clap::ValueHint::DirPath) - .takes_value(true) - .validator(|s| { - if Path::new(s).is_dir() { - return Ok(()); - } - Err(format!("'{}' is not a directory", s)) - }) .help("copy all SOURCE arguments into target-directory"), ) .arg( @@ -323,58 +316,62 @@ pub fn uu_app<'a>() -> Command<'a> { .short('T') .long(options::NO_TARGET_DIRECTORY) .conflicts_with(options::TARGET_DIRECTORY) - .help("Treat DEST as a regular file and not a directory"), + .help("Treat DEST as a regular file and not a directory") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::INTERACTIVE) .short('i') .long(options::INTERACTIVE) .overrides_with(options::NO_CLOBBER) - .help("ask before overwriting files"), + .help("ask before overwriting files") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::LINK) .short('l') .long(options::LINK) .overrides_with_all(MODE_ARGS) - .help("hard-link files instead of copying"), + .help("hard-link files instead of copying") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_CLOBBER) .short('n') .long(options::NO_CLOBBER) .overrides_with(options::INTERACTIVE) - .help("don't overwrite a file that already exists"), + .help("don't overwrite a file that already exists") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::RECURSIVE) .short('r') + .visible_short_alias('R') .long(options::RECURSIVE) // --archive sets this option - .help("copy directories recursively"), - ) - .arg( - Arg::new(options::RECURSIVE_ALIAS) - .short('R') - .help("same as -r"), + .help("copy directories recursively") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::STRIP_TRAILING_SLASHES) .long(options::STRIP_TRAILING_SLASHES) - .help("remove any trailing slashes from each SOURCE argument"), + .help("remove any trailing slashes from each SOURCE argument") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::VERBOSE) .short('v') .long(options::VERBOSE) - .help("explicitly state what is being done"), + .help("explicitly state what is being done") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SYMBOLIC_LINK) .short('s') .long(options::SYMBOLIC_LINK) .overrides_with_all(MODE_ARGS) - .help("make symbolic links instead of copying"), + .help("make symbolic links instead of copying") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::FORCE) @@ -384,7 +381,8 @@ pub fn uu_app<'a>() -> Command<'a> { "if an existing destination file cannot be opened, remove it and \ try again (this option is ignored when the -n option is also used). \ Currently not implemented for Windows.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::REMOVE_DESTINATION) @@ -394,7 +392,8 @@ pub fn uu_app<'a>() -> Command<'a> { "remove each existing destination file before attempting to open it \ (contrast with --force). On Windows, currently only works for \ writeable files.", - ), + ) + .action(ArgAction::SetTrue), ) .arg(backup_control::arguments::backup()) .arg(backup_control::arguments::backup_no_args()) @@ -406,36 +405,36 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "copy only when the SOURCE file is newer than the destination file \ or when the destination file is missing", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::REFLINK) .long(options::REFLINK) - .takes_value(true) .value_name("WHEN") .overrides_with_all(MODE_ARGS) .require_equals(true) .default_missing_value("always") .value_parser(["auto", "always", "never"]) - .min_values(0) + .num_args(0..=1) .help("control clone/CoW copies. See below"), ) .arg( Arg::new(options::ATTRIBUTES_ONLY) .long(options::ATTRIBUTES_ONLY) .overrides_with_all(MODE_ARGS) - .help("Don't copy the file data, just the attributes"), + .help("Don't copy the file data, just the attributes") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::PRESERVE) .long(options::PRESERVE) - .takes_value(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .use_value_delimiter(true) .value_parser(clap::builder::PossibleValuesParser::new( PRESERVABLE_ATTRIBUTES, )) - .min_values(0) + .num_args(0..) .value_name("ATTR_LIST") .overrides_with_all(&[ options::ARCHIVE, @@ -454,12 +453,12 @@ pub fn uu_app<'a>() -> Command<'a> { .short('p') .long(options::PRESERVE_DEFAULT_ATTRIBUTES) .overrides_with_all(&[options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE]) - .help("same as --preserve=mode,ownership(unix only),timestamps"), + .help("same as --preserve=mode,ownership(unix only),timestamps") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_PRESERVE) .long(options::NO_PRESERVE) - .takes_value(true) .value_name("ATTR_LIST") .overrides_with_all(&[ options::PRESERVE_DEFAULT_ATTRIBUTES, @@ -472,7 +471,8 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::PARENTS) .long(options::PARENTS) .alias(options::PARENT) - .help("use full source file name under DIRECTORY"), + .help("use full source file name under DIRECTORY") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_DEREFERENCE) @@ -480,19 +480,22 @@ pub fn uu_app<'a>() -> Command<'a> { .long(options::NO_DEREFERENCE) .overrides_with(options::DEREFERENCE) // -d sets this option - .help("never follow symbolic links in SOURCE"), + .help("never follow symbolic links in SOURCE") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DEREFERENCE) .short('L') .long(options::DEREFERENCE) .overrides_with(options::NO_DEREFERENCE) - .help("always follow symbolic links in SOURCE"), + .help("always follow symbolic links in SOURCE") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::CLI_SYMBOLIC_LINKS) .short('H') - .help("follow command-line symbolic links in SOURCE"), + .help("follow command-line symbolic links in SOURCE") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ARCHIVE) @@ -503,23 +506,25 @@ pub fn uu_app<'a>() -> Command<'a> { options::PRESERVE, options::NO_PRESERVE, ]) - .help("Same as -dR --preserve=all"), + .help("Same as -dR --preserve=all") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_DEREFERENCE_PRESERVE_LINKS) .short('d') - .help("same as --no-dereference --preserve=links"), + .help("same as --no-dereference --preserve=links") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ONE_FILE_SYSTEM) .short('x') .long(options::ONE_FILE_SYSTEM) - .help("stay on this file system"), + .help("stay on this file system") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SPARSE) .long(options::SPARSE) - .takes_value(true) .value_name("WHEN") .value_parser(["never", "auto", "always"]) .help("NotImplemented: control creation of sparse files. See below"), @@ -529,12 +534,12 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::COPY_CONTENTS) .long(options::COPY_CONTENTS) .overrides_with(options::ATTRIBUTES_ONLY) - .help("NotImplemented: copy contents of special files when recursive"), + .help("NotImplemented: copy contents of special files when recursive") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::CONTEXT) .long(options::CONTEXT) - .takes_value(true) .value_name("CTX") .help( "NotImplemented: set SELinux security context of destination file to \ @@ -544,29 +549,26 @@ pub fn uu_app<'a>() -> Command<'a> { // END TODO .arg( Arg::new(options::PATHS) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath), ) } #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let after_help = &*format!( - "{}\n{}", - LONG_HELP, - backup_control::BACKUP_CONTROL_LONG_HELP - ); - let matches = uu_app().after_help(after_help).try_get_matches_from(args); + let matches = uu_app() + .after_help(backup_control::BACKUP_CONTROL_LONG_HELP) + .try_get_matches_from(args); // The error is parsed here because we do not want version or help being printed to stderr. if let Err(e) = matches { - let mut app = uu_app().after_help(after_help); + let mut app = uu_app().after_help(backup_control::BACKUP_CONTROL_LONG_HELP); match e.kind() { - clap::ErrorKind::DisplayHelp => { + clap::error::ErrorKind::DisplayHelp => { app.print_help()?; } - clap::ErrorKind::DisplayVersion => println!("{}", app.render_version()), + clap::error::ErrorKind::DisplayVersion => println!("{}", app.render_version()), _ => return Err(Box::new(e.with_exit_code(1))), }; } else if let Ok(matches) = matches { @@ -603,9 +605,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { impl ClobberMode { fn from_matches(matches: &ArgMatches) -> Self { - if matches.contains_id(options::FORCE) { + if matches.get_flag(options::FORCE) { Self::Force - } else if matches.contains_id(options::REMOVE_DESTINATION) { + } else if matches.get_flag(options::REMOVE_DESTINATION) { Self::RemoveDestination } else { Self::Standard @@ -615,9 +617,9 @@ impl ClobberMode { impl OverwriteMode { fn from_matches(matches: &ArgMatches) -> Self { - if matches.contains_id(options::INTERACTIVE) { + if matches.get_flag(options::INTERACTIVE) { Self::Interactive(ClobberMode::from_matches(matches)) - } else if matches.contains_id(options::NO_CLOBBER) { + } else if matches.get_flag(options::NO_CLOBBER) { Self::NoClobber } else { Self::Clobber(ClobberMode::from_matches(matches)) @@ -627,13 +629,13 @@ impl OverwriteMode { impl CopyMode { fn from_matches(matches: &ArgMatches) -> Self { - if matches.contains_id(options::LINK) { + if matches.get_flag(options::LINK) { Self::Link - } else if matches.contains_id(options::SYMBOLIC_LINK) { + } else if matches.get_flag(options::SYMBOLIC_LINK) { Self::SymLink - } else if matches.contains_id(options::UPDATE) { + } else if matches.get_flag(options::UPDATE) { Self::Update - } else if matches.contains_id(options::ATTRIBUTES_ONLY) { + } else if matches.get_flag(options::ATTRIBUTES_ONLY) { Self::AttrOnly } else { Self::Copy @@ -693,14 +695,15 @@ impl Options { ]; for not_implemented_opt in not_implemented_opts { - if matches.contains_id(not_implemented_opt) { + if matches.contains_id(not_implemented_opt) + && matches.value_source(not_implemented_opt) + == Some(clap::parser::ValueSource::CommandLine) + { return Err(Error::NotImplemented(not_implemented_opt.to_string())); } } - let recursive = matches.contains_id(options::RECURSIVE) - || matches.contains_id(options::RECURSIVE_ALIAS) - || matches.contains_id(options::ARCHIVE); + let recursive = matches.get_flag(options::RECURSIVE) || matches.get_flag(options::ARCHIVE); let backup_mode = match backup_control::determine_backup_mode(matches) { Err(e) => return Err(Error::Backup(format!("{}", e))), @@ -712,11 +715,17 @@ impl Options { let overwrite = OverwriteMode::from_matches(matches); // Parse target directory options - let no_target_dir = matches.contains_id(options::NO_TARGET_DIRECTORY); + let no_target_dir = matches.get_flag(options::NO_TARGET_DIRECTORY); let target_dir = matches .get_one::(options::TARGET_DIRECTORY) .map(ToString::to_string); + if let Some(dir) = &target_dir { + if !Path::new(dir).is_dir() { + return Err(Error::NotADirectory(dir.clone())); + } + }; + // Parse attributes to preserve let mut preserve_attributes: Vec = if matches.contains_id(options::PRESERVE) { match matches.get_many::(options::PRESERVE) { @@ -734,12 +743,12 @@ impl Options { attributes } } - } else if matches.contains_id(options::ARCHIVE) { + } else if matches.get_flag(options::ARCHIVE) { // --archive is used. Same as --preserve=all add_all_attributes() - } else if matches.contains_id(options::NO_DEREFERENCE_PRESERVE_LINKS) { + } else if matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) { vec![Attribute::Links] - } else if matches.contains_id(options::PRESERVE_DEFAULT_ATTRIBUTES) { + } else if matches.get_flag(options::PRESERVE_DEFAULT_ATTRIBUTES) { DEFAULT_ATTRIBUTES.to_vec() } else { vec![] @@ -751,21 +760,21 @@ impl Options { preserve_attributes.sort_unstable(); let options = Self { - attributes_only: matches.contains_id(options::ATTRIBUTES_ONLY), - copy_contents: matches.contains_id(options::COPY_CONTENTS), - cli_dereference: matches.contains_id(options::CLI_SYMBOLIC_LINKS), + attributes_only: matches.get_flag(options::ATTRIBUTES_ONLY), + copy_contents: matches.get_flag(options::COPY_CONTENTS), + cli_dereference: matches.get_flag(options::CLI_SYMBOLIC_LINKS), copy_mode: CopyMode::from_matches(matches), // No dereference is set with -p, -d and --archive - dereference: !(matches.contains_id(options::NO_DEREFERENCE) - || matches.contains_id(options::NO_DEREFERENCE_PRESERVE_LINKS) - || matches.contains_id(options::ARCHIVE) + dereference: !(matches.get_flag(options::NO_DEREFERENCE) + || matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) + || matches.get_flag(options::ARCHIVE) || recursive) - || matches.contains_id(options::DEREFERENCE), - one_file_system: matches.contains_id(options::ONE_FILE_SYSTEM), - parents: matches.contains_id(options::PARENTS), - update: matches.contains_id(options::UPDATE), - verbose: matches.contains_id(options::VERBOSE), - strip_trailing_slashes: matches.contains_id(options::STRIP_TRAILING_SLASHES), + || matches.get_flag(options::DEREFERENCE), + one_file_system: matches.get_flag(options::ONE_FILE_SYSTEM), + parents: matches.get_flag(options::PARENTS), + update: matches.get_flag(options::UPDATE), + verbose: matches.get_flag(options::VERBOSE), + strip_trailing_slashes: matches.get_flag(options::STRIP_TRAILING_SLASHES), reflink_mode: { if let Some(reflink) = matches.get_one::(options::REFLINK) { match reflink.as_str() { diff --git a/src/uu/csplit/Cargo.toml b/src/uu/csplit/Cargo.toml index be55c1bf4..3d55fd5c3 100644 --- a/src/uu/csplit/Cargo.toml +++ b/src/uu/csplit/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/csplit.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } thiserror = "1.0" regex = "1.6.0" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } diff --git a/src/uu/csplit/src/csplit.rs b/src/uu/csplit/src/csplit.rs index 73af9b00d..295b319f3 100644 --- a/src/uu/csplit/src/csplit.rs +++ b/src/uu/csplit/src/csplit.rs @@ -12,7 +12,7 @@ use std::{ io::{BufRead, BufWriter, Write}, }; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use regex::Regex; use uucore::display::Quotable; use uucore::error::{FromIo, UResult}; @@ -52,10 +52,10 @@ pub struct CsplitOptions { impl CsplitOptions { fn new(matches: &ArgMatches) -> Self { - let keep_files = matches.contains_id(options::KEEP_FILES); - let quiet = matches.contains_id(options::QUIET); - let elide_empty_files = matches.contains_id(options::ELIDE_EMPTY_FILES); - let suppress_matched = matches.contains_id(options::SUPPRESS_MATCHED); + let keep_files = matches.get_flag(options::KEEP_FILES); + let quiet = matches.get_flag(options::QUIET); + let elide_empty_files = matches.get_flag(options::ELIDE_EMPTY_FILES); + let suppress_matched = matches.get_flag(options::SUPPRESS_MATCHED); Self { split_name: crash_if_err!( @@ -750,7 +750,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!()) .about(ABOUT) @@ -774,12 +774,14 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::KEEP_FILES) .short('k') .long(options::KEEP_FILES) - .help("do not remove output files on errors"), + .help("do not remove output files on errors") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SUPPRESS_MATCHED) .long(options::SUPPRESS_MATCHED) - .help("suppress the lines matching PATTERN"), + .help("suppress the lines matching PATTERN") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DIGITS) @@ -793,13 +795,15 @@ pub fn uu_app<'a>() -> Command<'a> { .short('s') .long(options::QUIET) .visible_alias("silent") - .help("do not print counts of output file sizes"), + .help("do not print counts of output file sizes") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ELIDE_EMPTY_FILES) .short('z') .long(options::ELIDE_EMPTY_FILES) - .help("remove empty output files"), + .help("remove empty output files") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::FILE) @@ -810,7 +814,7 @@ pub fn uu_app<'a>() -> Command<'a> { .arg( Arg::new(options::PATTERN) .hide(true) - .multiple_occurrences(true) + .action(clap::ArgAction::Append) .required(true), ) .after_help(LONG_HELP) diff --git a/src/uu/cut/Cargo.toml b/src/uu/cut/Cargo.toml index 9e78e49af..9f3185d71 100644 --- a/src/uu/cut/Cargo.toml +++ b/src/uu/cut/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/cut.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } memchr = "2" bstr = "0.2" diff --git a/src/uu/cut/src/cut.rs b/src/uu/cut/src/cut.rs index 7a8ced455..ecbf3470a 100644 --- a/src/uu/cut/src/cut.rs +++ b/src/uu/cut/src/cut.rs @@ -11,7 +11,7 @@ extern crate uucore; use bstr::io::BufReadExt; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::fs::File; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use std::path::Path; @@ -403,7 +403,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let delimiter_is_equal = args.contains(&"-d=".to_string()); // special case let matches = uu_app().try_get_matches_from(args)?; - let complement = matches.contains_id(options::COMPLEMENT); + let complement = matches.get_flag(options::COMPLEMENT); let mode_parse = match ( matches.get_one::(options::BYTES), @@ -421,7 +421,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .unwrap_or_default() .to_owned(), ), - zero_terminated: matches.contains_id(options::ZERO_TERMINATED), + zero_terminated: matches.get_flag(options::ZERO_TERMINATED), }, ) }), @@ -436,7 +436,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .unwrap_or_default() .to_owned(), ), - zero_terminated: matches.contains_id(options::ZERO_TERMINATED), + zero_terminated: matches.get_flag(options::ZERO_TERMINATED), }, ) }), @@ -453,8 +453,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { None => None, }; - let only_delimited = matches.contains_id(options::ONLY_DELIMITED); - let zero_terminated = matches.contains_id(options::ZERO_TERMINATED); + let only_delimited = matches.get_flag(options::ONLY_DELIMITED); + let zero_terminated = matches.get_flag(options::ZERO_TERMINATED); match matches.get_one::(options::DELIMITER).map(|s| s.as_str()) { Some(mut delim) => { @@ -514,7 +514,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Err("invalid input: The '--delimiter' ('-d') option only usable if printing a sequence of fields".into()) } Mode::Bytes(_, _) | Mode::Characters(_, _) - if matches.contains_id(options::ONLY_DELIMITED) => + if matches.get_flag(options::ONLY_DELIMITED) => { Err("invalid input: The '--only-delimited' ('-s') option only usable if printing a sequence of fields".into()) } @@ -534,7 +534,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()) .name(NAME) .version(crate_version!()) @@ -546,76 +546,63 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::BYTES) .short('b') .long(options::BYTES) - .takes_value(true) .help("filter byte columns from the input source") .allow_hyphen_values(true) - .value_name("LIST") - .display_order(1), + .value_name("LIST"), ) .arg( Arg::new(options::CHARACTERS) .short('c') .long(options::CHARACTERS) .help("alias for character mode") - .takes_value(true) .allow_hyphen_values(true) - .value_name("LIST") - .display_order(2), + .value_name("LIST"), ) .arg( Arg::new(options::DELIMITER) .short('d') .long(options::DELIMITER) .help("specify the delimiter character that separates fields in the input source. Defaults to Tab.") - .takes_value(true) - .value_name("DELIM") - .display_order(3), + .value_name("DELIM"), ) .arg( Arg::new(options::FIELDS) .short('f') .long(options::FIELDS) .help("filter field columns from the input source") - .takes_value(true) .allow_hyphen_values(true) - .value_name("LIST") - .display_order(4), + .value_name("LIST"), ) .arg( Arg::new(options::COMPLEMENT) .long(options::COMPLEMENT) .help("invert the filter - instead of displaying only the filtered columns, display all but those columns") - .takes_value(false) - .display_order(5), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ONLY_DELIMITED) - .short('s') + .short('s') .long(options::ONLY_DELIMITED) .help("in field mode, only print lines which contain the delimiter") - .takes_value(false) - .display_order(6), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ZERO_TERMINATED) - .short('z') + .short('z') .long(options::ZERO_TERMINATED) .help("instead of filtering columns based on line, filter columns based on \\0 (NULL character)") - .takes_value(false) - .display_order(8), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OUTPUT_DELIMITER) - .long(options::OUTPUT_DELIMITER) + .long(options::OUTPUT_DELIMITER) .help("in field mode, replace the delimiter in output lines with this option's argument") - .takes_value(true) - .value_name("NEW_DELIM") - .display_order(7), + .value_name("NEW_DELIM"), ) .arg( Arg::new(options::FILE) .hide(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::FilePath) ) } diff --git a/src/uu/date/Cargo.toml b/src/uu/date/Cargo.toml index 27dcb8456..de504f8c5 100644 --- a/src/uu/date/Cargo.toml +++ b/src/uu/date/Cargo.toml @@ -16,7 +16,7 @@ path = "src/date.rs" [dependencies] chrono = { version="^0.4.19", default-features=false, features=["std", "alloc", "clock"]} -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [target.'cfg(unix)'.dependencies] diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index abcfc4563..43b54898d 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -11,7 +11,7 @@ use chrono::{DateTime, FixedOffset, Local, Offset, Utc}; #[cfg(windows)] use chrono::{Datelike, Timelike}; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; #[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] use libc::{clock_settime, timespec, CLOCK_REALTIME}; use std::fs::File; @@ -160,7 +160,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map(|mut iter| iter.next().unwrap_or(&DATE.to_string()).as_str().into()) { Format::Iso8601(fmt) - } else if matches.contains_id(OPT_RFC_EMAIL) { + } else if matches.get_flag(OPT_RFC_EMAIL) { Format::Rfc5322 } else if let Some(fmt) = matches .get_one::(OPT_RFC_3339) @@ -191,7 +191,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; let settings = Settings { - utc: matches.contains_id(OPT_UNIVERSAL), + utc: matches.get_flag(OPT_UNIVERSAL), format, date_source, set_to, @@ -257,7 +257,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -267,7 +267,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_DATE) .short('d') .long(OPT_DATE) - .takes_value(true) .value_name("STRING") .help("display time described by STRING, not 'now'"), ) @@ -275,7 +274,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_FILE) .short('f') .long(OPT_FILE) - .takes_value(true) .value_name("DATEFILE") .value_hint(clap::ValueHint::FilePath) .help("like --date; once for each line of DATEFILE"), @@ -284,7 +282,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_ISO_8601) .short('I') .long(OPT_ISO_8601) - .takes_value(true) .value_name("FMT") .help(ISO_8601_HELP_STRING), ) @@ -292,25 +289,25 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_RFC_EMAIL) .short('R') .long(OPT_RFC_EMAIL) - .help(RFC_5322_HELP_STRING), + .help(RFC_5322_HELP_STRING) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_RFC_3339) .long(OPT_RFC_3339) - .takes_value(true) .value_name("FMT") .help(RFC_3339_HELP_STRING), ) .arg( Arg::new(OPT_DEBUG) .long(OPT_DEBUG) - .help("annotate the parsed date, and warn about questionable usage to stderr"), + .help("annotate the parsed date, and warn about questionable usage to stderr") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_REFERENCE) .short('r') .long(OPT_REFERENCE) - .takes_value(true) .value_name("FILE") .value_hint(clap::ValueHint::AnyPath) .help("display the last modification time of FILE"), @@ -319,7 +316,6 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_SET) .short('s') .long(OPT_SET) - .takes_value(true) .value_name("STRING") .help(OPT_SET_HELP_STRING), ) @@ -328,9 +324,10 @@ pub fn uu_app<'a>() -> Command<'a> { .short('u') .long(OPT_UNIVERSAL) .alias(OPT_UNIVERSAL_2) - .help("print or set Coordinated Universal Time (UTC)"), + .help("print or set Coordinated Universal Time (UTC)") + .action(ArgAction::SetTrue), ) - .arg(Arg::new(OPT_FORMAT).multiple_occurrences(false)) + .arg(Arg::new(OPT_FORMAT)) } /// Return the appropriate format string for the given settings. diff --git a/src/uu/dd/Cargo.toml b/src/uu/dd/Cargo.toml index e4bdb536d..871f8d806 100644 --- a/src/uu/dd/Cargo.toml +++ b/src/uu/dd/Cargo.toml @@ -16,7 +16,7 @@ path = "src/dd.rs" [dependencies] byte-unit = "4.0" -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } gcd = "2.0" libc = "0.2" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 8e4493e4e..f9864f7ee 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -769,13 +769,13 @@ 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!()) .about(ABOUT) .after_help(AFTER_HELP) .infer_long_args(true) - .arg(Arg::new(options::OPERANDS).multiple_values(true)) + .arg(Arg::new(options::OPERANDS).num_args(1..)) } #[cfg(test)] diff --git a/src/uu/df/Cargo.toml b/src/uu/df/Cargo.toml index 0ee499b99..e0e15304f 100644 --- a/src/uu/df/Cargo.toml +++ b/src/uu/df/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/df.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["libc", "fsext"] } unicode-width = "0.1.9" diff --git a/src/uu/df/src/blocks.rs b/src/uu/df/src/blocks.rs index 1c90b0033..79151f817 100644 --- a/src/uu/df/src/blocks.rs +++ b/src/uu/df/src/blocks.rs @@ -172,7 +172,7 @@ pub(crate) fn read_block_size(matches: &ArgMatches) -> Result Result, ColumnError> { match ( - matches.contains_id(OPT_PRINT_TYPE), - matches.contains_id(OPT_INODES), + matches.get_flag(OPT_PRINT_TYPE), + matches.get_flag(OPT_INODES), matches.value_source(OPT_OUTPUT) == Some(ValueSource::CommandLine), ) { (false, false, false) => Ok(vec![ diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index 5bfe17a99..8d26bc6f8 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -21,7 +21,7 @@ use uucore::fsext::{read_fs_list, MountInfo}; use uucore::parse_size::ParseSizeError; use uucore::{format_usage, show}; -use clap::{crate_version, Arg, ArgMatches, Command, ValueSource}; +use clap::{crate_version, parser::ValueSource, Arg, ArgAction, ArgMatches, Command}; use std::error::Error; use std::ffi::OsString; @@ -187,9 +187,9 @@ impl Options { } Ok(Self { - show_local_fs: matches.contains_id(OPT_LOCAL), - show_all_fs: matches.contains_id(OPT_ALL), - sync: matches.contains_id(OPT_SYNC), + show_local_fs: matches.get_flag(OPT_LOCAL), + show_all_fs: matches.get_flag(OPT_ALL), + sync: matches.get_flag(OPT_SYNC), block_size: read_block_size(matches).map_err(|e| match e { ParseSizeError::InvalidSuffix(s) => OptionsError::InvalidSuffix(s), ParseSizeError::SizeTooBig(_) => OptionsError::BlockSizeTooLarge( @@ -201,13 +201,13 @@ impl Options { ParseSizeError::ParseFailure(s) => OptionsError::InvalidBlockSize(s), })?, header_mode: { - if matches.contains_id(OPT_HUMAN_READABLE_BINARY) - || matches.contains_id(OPT_HUMAN_READABLE_DECIMAL) + if matches.get_flag(OPT_HUMAN_READABLE_BINARY) + || matches.get_flag(OPT_HUMAN_READABLE_DECIMAL) { HeaderMode::HumanReadable - } else if matches.contains_id(OPT_PORTABILITY) { + } else if matches.get_flag(OPT_PORTABILITY) { HeaderMode::PosixPortability - // contains_id() doesn't work here, it always returns true because OPT_OUTPUT has + // get_flag() doesn't work here, it always returns true because OPT_OUTPUT has // default values and hence is always present } else if matches.value_source(OPT_OUTPUT) == Some(ValueSource::CommandLine) { HeaderMode::Output @@ -216,9 +216,9 @@ impl Options { } }, human_readable: { - if matches.contains_id(OPT_HUMAN_READABLE_BINARY) { + if matches.get_flag(OPT_HUMAN_READABLE_BINARY) { Some(HumanReadable::Binary) - } else if matches.contains_id(OPT_HUMAN_READABLE_DECIMAL) { + } else if matches.get_flag(OPT_HUMAN_READABLE_DECIMAL) { Some(HumanReadable::Decimal) } else { None @@ -226,7 +226,7 @@ impl Options { }, include, exclude, - show_total: matches.contains_id(OPT_TOTAL), + show_total: matches.get_flag(OPT_TOTAL), columns: Column::from_matches(matches).map_err(OptionsError::ColumnError)?, }) } @@ -443,7 +443,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { #[cfg(windows)] { - if matches.contains_id(OPT_INODES) { + if matches.get_flag(OPT_INODES) { println!("{}: doesn't support -i option", uucore::util_name()); return Ok(()); } @@ -482,30 +482,32 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) .override_usage(format_usage(USAGE)) .after_help(LONG_HELP) .infer_long_args(true) + .disable_help_flag(true) .arg( Arg::new(OPT_HELP) .long(OPT_HELP) - .help("Print help information."), + .help("Print help information.") + .action(ArgAction::Help), ) .arg( Arg::new(OPT_ALL) .short('a') .long("all") .overrides_with(OPT_ALL) - .help("include dummy file systems"), + .help("include dummy file systems") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_BLOCKSIZE) .short('B') .long("block-size") - .takes_value(true) .value_name("SIZE") .overrides_with_all(&[OPT_KILO, OPT_BLOCKSIZE]) .help( @@ -517,57 +519,63 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_TOTAL) .long("total") .overrides_with(OPT_TOTAL) - .help("produce a grand total"), + .help("produce a grand total") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_HUMAN_READABLE_BINARY) .short('h') .long("human-readable") .overrides_with_all(&[OPT_HUMAN_READABLE_DECIMAL, OPT_HUMAN_READABLE_BINARY]) - .help("print sizes in human readable format (e.g., 1K 234M 2G)"), + .help("print sizes in human readable format (e.g., 1K 234M 2G)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_HUMAN_READABLE_DECIMAL) .short('H') .long("si") .overrides_with_all(&[OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL]) - .help("likewise, but use powers of 1000 not 1024"), + .help("likewise, but use powers of 1000 not 1024") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_INODES) .short('i') .long("inodes") .overrides_with(OPT_INODES) - .help("list inode information instead of block usage"), + .help("list inode information instead of block usage") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_KILO) .short('k') .help("like --block-size=1K") - .overrides_with_all(&[OPT_BLOCKSIZE, OPT_KILO]), + .overrides_with_all(&[OPT_BLOCKSIZE, OPT_KILO]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_LOCAL) .short('l') .long("local") .overrides_with(OPT_LOCAL) - .help("limit listing to local file systems"), + .help("limit listing to local file systems") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_NO_SYNC) .long("no-sync") .overrides_with_all(&[OPT_SYNC, OPT_NO_SYNC]) - .help("do not invoke sync before getting usage info (default)"), + .help("do not invoke sync before getting usage info (default)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_OUTPUT) .long("output") - .takes_value(true) .value_name("FIELD_LIST") - .min_values(0) + .action(ArgAction::Append) + .num_args(0..) .require_equals(true) .use_value_delimiter(true) - .multiple_occurrences(true) .value_parser(OUTPUT_FIELD_LIST) .default_missing_values(&OUTPUT_FIELD_LIST) .default_values(&["source", "size", "used", "avail", "pcent", "target"]) @@ -582,22 +590,23 @@ pub fn uu_app<'a>() -> Command<'a> { .short('P') .long("portability") .overrides_with(OPT_PORTABILITY) - .help("use the POSIX output format"), + .help("use the POSIX output format") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_SYNC) .long("sync") .overrides_with_all(&[OPT_NO_SYNC, OPT_SYNC]) - .help("invoke sync before getting usage info (non-windows only)"), + .help("invoke sync before getting usage info (non-windows only)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_TYPE) .short('t') .long("type") .value_parser(ValueParser::os_string()) - .takes_value(true) .value_name("TYPE") - .multiple_occurrences(true) + .action(ArgAction::Append) .help("limit listing to file systems of type TYPE"), ) .arg( @@ -605,22 +614,22 @@ pub fn uu_app<'a>() -> Command<'a> { .short('T') .long("print-type") .overrides_with(OPT_PRINT_TYPE) - .help("print file system type"), + .help("print file system type") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_EXCLUDE_TYPE) .short('x') .long("exclude-type") + .action(ArgAction::Append) .value_parser(ValueParser::os_string()) - .takes_value(true) .value_name("TYPE") .use_value_delimiter(true) - .multiple_occurrences(true) .help("limit listing to file systems not of type TYPE"), ) .arg( Arg::new(OPT_PATHS) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath), ) } diff --git a/src/uu/dir/Cargo.toml b/src/uu/dir/Cargo.toml index 488dd22da..37d16cee8 100644 --- a/src/uu/dir/Cargo.toml +++ b/src/uu/dir/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/dir.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo", "env"] } +clap = { version = "4.0", features = ["wrap_help", "cargo", "env"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } selinux = { version = "0.3", optional = true } uu_ls = { version = ">=0.0.16", path="../ls"} diff --git a/src/uu/dir/src/dir.rs b/src/uu/dir/src/dir.rs index 22932d9ae..6caf7bbe8 100644 --- a/src/uu/dir/src/dir.rs +++ b/src/uu/dir/src/dir.rs @@ -25,21 +25,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // If not, we will use dir default formatting and quoting style options if !matches.contains_id(options::QUOTING_STYLE) - && !matches.contains_id(options::quoting::C) - && !matches.contains_id(options::quoting::ESCAPE) - && !matches.contains_id(options::quoting::LITERAL) + && !matches.get_flag(options::quoting::C) + && !matches.get_flag(options::quoting::ESCAPE) + && !matches.get_flag(options::quoting::LITERAL) { default_quoting_style = true; } if !matches.contains_id(options::FORMAT) - && !matches.contains_id(options::format::ACROSS) - && !matches.contains_id(options::format::COLUMNS) - && !matches.contains_id(options::format::COMMAS) - && !matches.contains_id(options::format::LONG) - && !matches.contains_id(options::format::LONG_NO_GROUP) - && !matches.contains_id(options::format::LONG_NO_OWNER) - && !matches.contains_id(options::format::LONG_NUMERIC_UID_GID) - && !matches.contains_id(options::format::ONE_LINE) + && !matches.get_flag(options::format::ACROSS) + && !matches.get_flag(options::format::COLUMNS) + && !matches.get_flag(options::format::COMMAS) + && !matches.get_flag(options::format::LONG) + && !matches.get_flag(options::format::LONG_NO_GROUP) + && !matches.get_flag(options::format::LONG_NO_OWNER) + && !matches.get_flag(options::format::LONG_NUMERIC_UID_GID) + && !matches.get_flag(options::format::ONE_LINE) { default_format_style = true; } @@ -66,6 +66,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // To avoid code duplication, we reuse ls uu_app function which has the same // arguments. However, coreutils won't compile if one of the utils is missing // an uu_app function, so we return the `ls` app. -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { uu_ls::uu_app() } diff --git a/src/uu/dircolors/Cargo.toml b/src/uu/dircolors/Cargo.toml index 1c5a1b8f8..0c2294a57 100644 --- a/src/uu/dircolors/Cargo.toml +++ b/src/uu/dircolors/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/dircolors.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } glob = "0.3.0" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/dircolors/src/dircolors.rs b/src/uu/dircolors/src/dircolors.rs index 054c6205f..86beb9e90 100644 --- a/src/uu/dircolors/src/dircolors.rs +++ b/src/uu/dircolors/src/dircolors.rs @@ -13,7 +13,7 @@ use std::env; use std::fs::File; use std::io::{BufRead, BufReader}; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use uucore::display::Quotable; use uucore::error::{UResult, USimpleError, UUsageError}; @@ -75,9 +75,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // clap provides .conflicts_with / .conflicts_with_all, but we want to // manually handle conflicts so we can match the output of GNU coreutils - if (matches.contains_id(options::C_SHELL) || matches.contains_id(options::BOURNE_SHELL)) - && (matches.contains_id(options::PRINT_DATABASE) - || matches.contains_id(options::PRINT_LS_COLORS)) + if (matches.get_flag(options::C_SHELL) || matches.get_flag(options::BOURNE_SHELL)) + && (matches.get_flag(options::PRINT_DATABASE) || matches.get_flag(options::PRINT_LS_COLORS)) { return Err(UUsageError::new( 1, @@ -86,15 +85,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )); } - if matches.contains_id(options::PRINT_DATABASE) && matches.contains_id(options::PRINT_LS_COLORS) - { + if matches.get_flag(options::PRINT_DATABASE) && matches.get_flag(options::PRINT_LS_COLORS) { return Err(UUsageError::new( 1, "options --print-database and --print-ls-colors are mutually exclusive", )); } - if matches.contains_id(options::PRINT_DATABASE) { + if matches.get_flag(options::PRINT_DATABASE) { if !files.is_empty() { return Err(UUsageError::new( 1, @@ -109,11 +107,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { return Ok(()); } - let mut out_format = if matches.contains_id(options::C_SHELL) { + let mut out_format = if matches.get_flag(options::C_SHELL) { OutputFmt::CShell - } else if matches.contains_id(options::BOURNE_SHELL) { + } else if matches.get_flag(options::BOURNE_SHELL) { OutputFmt::Shell - } else if matches.contains_id(options::PRINT_LS_COLORS) { + } else if matches.get_flag(options::PRINT_LS_COLORS) { OutputFmt::Display } else { OutputFmt::Unknown @@ -168,7 +166,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!()) .about(ABOUT) @@ -182,7 +180,7 @@ pub fn uu_app<'a>() -> Command<'a> { .visible_alias("bourne-shell") .overrides_with(options::C_SHELL) .help("output Bourne shell code to set LS_COLORS") - .display_order(1), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::C_SHELL) @@ -191,26 +189,26 @@ pub fn uu_app<'a>() -> Command<'a> { .visible_alias("c-shell") .overrides_with(options::BOURNE_SHELL) .help("output C shell code to set LS_COLORS") - .display_order(2), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::PRINT_DATABASE) .long("print-database") .short('p') .help("print the byte counts") - .display_order(3), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::PRINT_LS_COLORS) .long("print-ls-colors") .help("output fully escaped colors for display") - .display_order(4), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::FILE) .hide(true) .value_hint(clap::ValueHint::FilePath) - .multiple_occurrences(true), + .action(ArgAction::Append), ) } diff --git a/src/uu/dirname/Cargo.toml b/src/uu/dirname/Cargo.toml index 907b77e2c..4b0320360 100644 --- a/src/uu/dirname/Cargo.toml +++ b/src/uu/dirname/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/dirname.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index 2bfdbb2e9..1f15ccdca 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -5,7 +5,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::path::Path; use uucore::display::print_verbatim; use uucore::error::{UResult, UUsageError}; @@ -19,24 +19,20 @@ mod options { pub const DIR: &str = "dir"; } -fn get_long_usage() -> String { - String::from( - "Output each NAME with its last non-slash component and trailing slashes \n\ - removed; if NAME contains no /'s, output '.' (meaning the current directory).", - ) +fn get_long_usage() -> &'static str { + "Output each NAME with its last non-slash component and trailing slashes \n\ + removed; if NAME contains no /'s, output '.' (meaning the current directory)." } #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args.collect_lossy(); - let after_help = get_long_usage(); - let matches = uu_app() - .after_help(&after_help[..]) + .after_help(get_long_usage()) .try_get_matches_from(args)?; - let separator = if matches.contains_id(options::ZERO) { + let separator = if matches.get_flag(options::ZERO) { "\0" } else { "\n" @@ -76,7 +72,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .about(ABOUT) .version(crate_version!()) @@ -86,12 +82,13 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::ZERO) .long(options::ZERO) .short('z') - .help("separate output with NUL rather than newline"), + .help("separate output with NUL rather than newline") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DIR) .hide(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath), ) } diff --git a/src/uu/du/Cargo.toml b/src/uu/du/Cargo.toml index c0137726c..e41cc753e 100644 --- a/src/uu/du/Cargo.toml +++ b/src/uu/du/Cargo.toml @@ -18,7 +18,7 @@ path = "src/du.rs" chrono = { version="^0.4.19", default-features=false, features=["std", "alloc", "clock"]} # For the --exclude & --exclude-from options glob = "0.3.0" -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 493ddd3f8..18e9a4af3 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -10,6 +10,7 @@ extern crate uucore; use chrono::prelude::DateTime; use chrono::Local; +use clap::ArgAction; use clap::{crate_version, Arg, ArgMatches, Command}; use glob::Pattern; use std::collections::HashSet; @@ -282,9 +283,9 @@ fn read_block_size(s: Option<&str>) -> u64 { } fn choose_size(matches: &ArgMatches, stat: &Stat) -> u64 { - if matches.contains_id(options::INODES) { + if matches.get_flag(options::INODES) { stat.inodes - } else if matches.contains_id(options::APPARENT_SIZE) || matches.contains_id(options::BYTES) { + } else if matches.get_flag(options::APPARENT_SIZE) || matches.get_flag(options::BYTES) { stat.size } else { // The st_blocks field indicates the number of blocks allocated to the file, 512-byte units. @@ -501,7 +502,7 @@ fn build_exclude_patterns(matches: &ArgMatches) -> UResult> { let mut exclude_patterns = Vec::new(); for f in excludes_iterator.chain(exclude_from_iterator) { - if matches.contains_id(options::VERBOSE) { + if matches.get_flag(options::VERBOSE) { println!("adding {:?} to the exclude list ", &f); } match parse_glob::from_str(&f) { @@ -519,7 +520,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; - let summarize = matches.contains_id(options::SUMMARIZE); + let summarize = matches.get_flag(options::SUMMARIZE); let max_depth = parse_depth( matches @@ -529,14 +530,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )?; let options = Options { - all: matches.contains_id(options::ALL), + all: matches.get_flag(options::ALL), max_depth, - total: matches.contains_id(options::TOTAL), - separate_dirs: matches.contains_id(options::SEPARATE_DIRS), - one_file_system: matches.contains_id(options::ONE_FILE_SYSTEM), - dereference: matches.contains_id(options::DEREFERENCE), - inodes: matches.contains_id(options::INODES), - verbose: matches.contains_id(options::VERBOSE), + total: matches.get_flag(options::TOTAL), + separate_dirs: matches.get_flag(options::SEPARATE_DIRS), + one_file_system: matches.get_flag(options::ONE_FILE_SYSTEM), + dereference: matches.get_flag(options::DEREFERENCE), + inodes: matches.get_flag(options::INODES), + verbose: matches.get_flag(options::VERBOSE), }; let files = match matches.get_one::(options::FILE) { @@ -549,7 +550,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; if options.inodes - && (matches.contains_id(options::APPARENT_SIZE) || matches.contains_id(options::BYTES)) + && (matches.get_flag(options::APPARENT_SIZE) || matches.get_flag(options::BYTES)) { show_warning!("options --apparent-size and -b are ineffective with --inodes"); } @@ -565,19 +566,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::THRESHOLD))) }); - let multiplier: u64 = if matches.contains_id(options::SI) { + let multiplier: u64 = if matches.get_flag(options::SI) { 1000 } else { 1024 }; let convert_size_fn = { - if matches.contains_id(options::HUMAN_READABLE) || matches.contains_id(options::SI) { + if matches.get_flag(options::HUMAN_READABLE) || matches.get_flag(options::SI) { convert_size_human - } else if matches.contains_id(options::BYTES) { + } else if matches.get_flag(options::BYTES) { convert_size_b - } else if matches.contains_id(options::BLOCK_SIZE_1K) { + } else if matches.get_flag(options::BLOCK_SIZE_1K) { convert_size_k - } else if matches.contains_id(options::BLOCK_SIZE_1M) { + } else if matches.get_flag(options::BLOCK_SIZE_1M) { convert_size_m } else { convert_size_other @@ -594,7 +595,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let time_format_str = parse_time_style(matches.get_one::("time-style").map(|s| s.as_str()))?; - let line_separator = if matches.contains_id(options::NULL) { + let line_separator = if matches.get_flag(options::NULL) { "\0" } else { "\n" @@ -710,23 +711,26 @@ fn parse_depth(max_depth_str: Option<&str>, summarize: bool) -> UResult() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) .after_help(LONG_HELP) .override_usage(format_usage(USAGE)) .infer_long_args(true) + .disable_help_flag(true) .arg( Arg::new(options::HELP) .long(options::HELP) .help("Print help information.") + .action(ArgAction::Help) ) .arg( Arg::new(options::ALL) .short('a') .long(options::ALL) - .help("write counts for all files, not just directories"), + .help("write counts for all files, not just directories") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::APPARENT_SIZE) @@ -736,6 +740,7 @@ pub fn uu_app<'a>() -> Command<'a> { although the apparent size is usually smaller, it may be larger due to holes \ in ('sparse') files, internal fragmentation, indirect blocks, and the like" ) + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::BLOCK_SIZE) @@ -752,12 +757,14 @@ pub fn uu_app<'a>() -> Command<'a> { .short('b') .long("bytes") .help("equivalent to '--apparent-size --block-size=1'") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::TOTAL) .long("total") .short('c') .help("produce a grand total") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::MAX_DEPTH) @@ -775,6 +782,7 @@ pub fn uu_app<'a>() -> Command<'a> { .long("human-readable") .short('h') .help("print sizes in human readable format (e.g., 1K 234M 2G)") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::INODES) @@ -782,70 +790,81 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "list inode usage information instead of block usage like --block-size=1K" ) + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::BLOCK_SIZE_1K) .short('k') .help("like --block-size=1K") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::COUNT_LINKS) .short('l') .long("count-links") .help("count sizes many times if hard linked") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::DEREFERENCE) .short('L') .long(options::DEREFERENCE) .help("dereference all symbolic links") + .action(ArgAction::SetTrue) ) // .arg( // Arg::new("no-dereference") // .short('P') // .long("no-dereference") // .help("don't follow any symbolic links (this is the default)") + // .action(ArgAction::SetTrue), // ) .arg( Arg::new(options::BLOCK_SIZE_1M) .short('m') .help("like --block-size=1M") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::NULL) .short('0') .long("null") .help("end each output line with 0 byte rather than newline") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::SEPARATE_DIRS) .short('S') .long("separate-dirs") .help("do not include size of subdirectories") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::SUMMARIZE) .short('s') .long("summarize") .help("display only a total for each argument") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::SI) .long(options::SI) .help("like -h, but use powers of 1000 not 1024") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::ONE_FILE_SYSTEM) .short('x') .long(options::ONE_FILE_SYSTEM) .help("skip directories on different file systems") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::THRESHOLD) .short('t') .long(options::THRESHOLD) .value_name("SIZE") - .number_of_values(1) + .num_args(1) .allow_hyphen_values(true) .help("exclude entries smaller than SIZE if positive, \ or entries greater than SIZE if negative") @@ -855,13 +874,14 @@ pub fn uu_app<'a>() -> Command<'a> { .short('v') .long("verbose") .help("verbose mode (option not present in GNU/Coreutils)") + .action(ArgAction::SetTrue) ) .arg( Arg::new(options::EXCLUDE) .long(options::EXCLUDE) .value_name("PATTERN") .help("exclude files that match PATTERN") - .multiple_occurrences(true) + .action(ArgAction::Append) ) .arg( Arg::new(options::EXCLUDE_FROM) @@ -870,15 +890,14 @@ pub fn uu_app<'a>() -> Command<'a> { .value_name("FILE") .value_hint(clap::ValueHint::FilePath) .help("exclude files that match any pattern in FILE") - .multiple_occurrences(true) - + .action(ArgAction::Append) ) .arg( Arg::new(options::TIME) .long(options::TIME) .value_name("WORD") .require_equals(true) - .min_values(0) + .num_args(0..) .value_parser(["atime", "access", "use", "ctime", "status", "birth", "creation"]) .help( "show time of the last modification of any file in the \ @@ -899,7 +918,7 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::FILE) .hide(true) .value_hint(clap::ValueHint::AnyPath) - .multiple_occurrences(true) + .action(ArgAction::Append) ) } diff --git a/src/uu/echo/Cargo.toml b/src/uu/echo/Cargo.toml index e557e68fb..870a134b5 100644 --- a/src/uu/echo/Cargo.toml +++ b/src/uu/echo/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/echo.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/echo/src/echo.rs b/src/uu/echo/src/echo.rs index 6f4d2e674..ebf0d46e7 100644 --- a/src/uu/echo/src/echo.rs +++ b/src/uu/echo/src/echo.rs @@ -6,7 +6,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::io::{self, Write}; use std::iter::Peekable; use std::str::Chars; @@ -113,8 +113,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args.collect_lossy(); let matches = uu_app().get_matches_from(args); - let no_newline = matches.contains_id(options::NO_NEWLINE); - let escaped = matches.contains_id(options::ENABLE_BACKSLASH_ESCAPE); + let no_newline = matches.get_flag(options::NO_NEWLINE); + let escaped = matches.get_flag(options::ENABLE_BACKSLASH_ESCAPE); let values: Vec = match matches.get_many::(options::STRING) { Some(s) => s.map(|s| s.to_string()).collect(), None => vec!["".to_string()], @@ -124,7 +124,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map_err_context(|| "could not write to stdout".to_string()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .name(NAME) // TrailingVarArg specifies the final positional argument is a VarArg @@ -141,21 +141,21 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::NO_NEWLINE) .short('n') .help("do not output the trailing newline") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ENABLE_BACKSLASH_ESCAPE) .short('e') .help("enable interpretation of backslash escapes") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DISABLE_BACKSLASH_ESCAPE) .short('E') .help("disable interpretation of backslash escapes (default)") - .takes_value(false), + .action(ArgAction::SetTrue), ) - .arg(Arg::new(options::STRING).multiple_occurrences(true)) + .arg(Arg::new(options::STRING).action(ArgAction::Append)) } fn execute(no_newline: bool, escaped: bool, free: &[String]) -> io::Result<()> { diff --git a/src/uu/env/Cargo.toml b/src/uu/env/Cargo.toml index 66a4b7139..da9cdeab6 100644 --- a/src/uu/env/Cargo.toml +++ b/src/uu/env/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/env.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } rust-ini = "0.18.0" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["signals"]} diff --git a/src/uu/env/src/env.rs b/src/uu/env/src/env.rs index aea1a2525..01f63a1c8 100644 --- a/src/uu/env/src/env.rs +++ b/src/uu/env/src/env.rs @@ -16,7 +16,7 @@ extern crate clap; #[macro_use] extern crate uucore; -use clap::{Arg, Command}; +use clap::{Arg, ArgAction, Command}; use ini::Ini; #[cfg(unix)] use nix::sys::signal::{raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; @@ -126,57 +126,69 @@ fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b (progname, &args[..]) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(crate_name!()) .version(crate_version!()) .about(ABOUT) .override_usage(format_usage(USAGE)) .after_help(AFTER_HELP) - .allow_external_subcommands(true) .infer_long_args(true) - .arg(Arg::new("ignore-environment") - .short('i') - .long("ignore-environment") - .help("start with an empty environment")) - .arg(Arg::new("chdir") - .short('C') // GNU env compatibility - .long("chdir") - .takes_value(true) - .number_of_values(1) - .value_name("DIR") - .value_hint(clap::ValueHint::DirPath) - .help("change working directory to DIR")) - .arg(Arg::new("null") - .short('0') - .long("null") - .help("end each output line with a 0 byte rather than a newline (only valid when \ - printing the environment)")) - .arg(Arg::new("file") - .short('f') - .long("file") - .takes_value(true) - .number_of_values(1) - .value_name("PATH") - .value_hint(clap::ValueHint::FilePath) - .multiple_occurrences(true) - .help("read and set variables from a \".env\"-style configuration file (prior to any \ - unset and/or set)")) - .arg(Arg::new("unset") - .short('u') - .long("unset") - .takes_value(true) - .number_of_values(1) - .value_name("NAME") - .multiple_occurrences(true) - .help("remove variable from the environment")) + .trailing_var_arg(true) + .arg( + Arg::new("ignore-environment") + .short('i') + .long("ignore-environment") + .help("start with an empty environment") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("chdir") + .short('C') // GNU env compatibility + .long("chdir") + .number_of_values(1) + .value_name("DIR") + .value_hint(clap::ValueHint::DirPath) + .help("change working directory to DIR"), + ) + .arg( + Arg::new("null") + .short('0') + .long("null") + .help( + "end each output line with a 0 byte rather than a newline (only \ + valid when printing the environment)", + ) + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("file") + .short('f') + .long("file") + .value_name("PATH") + .value_hint(clap::ValueHint::FilePath) + .action(ArgAction::Append) + .help( + "read and set variables from a \".env\"-style configuration file \ + (prior to any unset and/or set)", + ), + ) + .arg( + Arg::new("unset") + .short('u') + .long("unset") + .value_name("NAME") + .action(ArgAction::Append) + .help("remove variable from the environment"), + ) + .arg(Arg::new("vars").action(ArgAction::Append)) } fn run_env(args: impl uucore::Args) -> UResult<()> { let app = uu_app(); let matches = app.try_get_matches_from(args).with_exit_code(125)?; - let ignore_env = matches.contains_id("ignore-environment"); - let null = matches.contains_id("null"); + let ignore_env = matches.get_flag("ignore-environment"); + let null = matches.get_flag("null"); let running_directory = matches.get_one::("chdir").map(|s| s.as_str()); let files = match matches.get_many::("file") { Some(v) => v.map(|s| s.as_str()).collect(), @@ -210,32 +222,24 @@ fn run_env(args: impl uucore::Args) -> UResult<()> { }; } - // we handle the name, value pairs and the program to be executed by treating them as external - // subcommands in clap - if let Some((external, matches)) = matches.subcommand() { - let mut begin_prog_opts = false; - - if external == "-" { - // "-" implies -i and stop parsing opts - opts.ignore_env = true; - } else { - begin_prog_opts = parse_name_value_opt(&mut opts, external)?; + let mut begin_prog_opts = false; + if let Some(mut iter) = matches.get_many::("vars") { + // read NAME=VALUE arguments (and up to a single program argument) + while !begin_prog_opts { + if let Some(opt) = iter.next() { + if opt == "-" { + opts.ignore_env = true; + } else { + begin_prog_opts = parse_name_value_opt(&mut opts, opt)?; + } + } else { + break; + } } - if let Some(mut iter) = matches.get_many::("") { - // read NAME=VALUE arguments (and up to a single program argument) - while !begin_prog_opts { - if let Some(opt) = iter.next() { - begin_prog_opts = parse_name_value_opt(&mut opts, opt)?; - } else { - break; - } - } - - // read any leftover program arguments - for opt in iter { - parse_program_opt(&mut opts, opt)?; - } + // read any leftover program arguments + for opt in iter { + parse_program_opt(&mut opts, opt)?; } } diff --git a/src/uu/expand/Cargo.toml b/src/uu/expand/Cargo.toml index 3604be070..65660d50e 100644 --- a/src/uu/expand/Cargo.toml +++ b/src/uu/expand/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/expand.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } unicode-width = "0.1.5" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/expand/src/expand.rs b/src/uu/expand/src/expand.rs index 4b72dcadf..31905ce58 100644 --- a/src/uu/expand/src/expand.rs +++ b/src/uu/expand/src/expand.rs @@ -12,7 +12,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use std::error::Error; use std::fmt; use std::fs::File; @@ -216,8 +216,8 @@ impl Options { None => (RemainingMode::None, vec![DEFAULT_TABSTOP]), }; - let iflag = matches.contains_id(options::INITIAL); - let uflag = !matches.contains_id(options::NO_UTF8); + let iflag = matches.get_flag(options::INITIAL); + let uflag = !matches.get_flag(options::NO_UTF8); // avoid allocations when dumping out long sequences of spaces // by precomputing the longest string of spaces we will ever need @@ -276,7 +276,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { expand(&Options::new(&matches)?).map_err_context(|| "failed to write output".to_string()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -287,15 +287,15 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::INITIAL) .long(options::INITIAL) .short('i') - .help("do not convert tabs after non blanks"), + .help("do not convert tabs after non blanks") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::TABS) .long(options::TABS) .short('t') .value_name("N, LIST") - .takes_value(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .help( "have tabs N characters apart, not 8 or use comma separated list \ of explicit tab positions", @@ -305,13 +305,13 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::NO_UTF8) .long(options::NO_UTF8) .short('U') - .help("interpret input file as 8-bit ASCII rather than UTF-8"), + .help("interpret input file as 8-bit ASCII rather than UTF-8") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::FILES) - .multiple_occurrences(true) + .action(ArgAction::Append) .hide(true) - .takes_value(true) .value_hint(clap::ValueHint::FilePath), ) } diff --git a/src/uu/expr/Cargo.toml b/src/uu/expr/Cargo.toml index 52ddc10d1..e3f8b1d57 100644 --- a/src/uu/expr/Cargo.toml +++ b/src/uu/expr/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/expr.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } num-bigint = "0.4.0" num-traits = "0.2.15" onig = { version = "~6.4", default-features = false } diff --git a/src/uu/expr/expr.md b/src/uu/expr/expr.md new file mode 100644 index 000000000..1faa88781 --- /dev/null +++ b/src/uu/expr/expr.md @@ -0,0 +1,59 @@ +# expr + +## About + +Print the value of EXPRESSION to standard output + +## Usage +``` +expr [EXPRESSION] +expr [OPTIONS] +``` + +## After help + +Print the value of EXPRESSION to standard output. A blank line below +separates increasing precedence groups. EXPRESSION may be: + + ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2 + + ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0 + + ARG1 < ARG2 ARG1 is less than ARG2 + ARG1 <= ARG2 ARG1 is less than or equal to ARG2 + ARG1 = ARG2 ARG1 is equal to ARG2 + ARG1 != ARG2 ARG1 is unequal to ARG2 + ARG1 >= ARG2 ARG1 is greater than or equal to ARG2 + ARG1 > ARG2 ARG1 is greater than ARG2 + + ARG1 + ARG2 arithmetic sum of ARG1 and ARG2 + ARG1 - ARG2 arithmetic difference of ARG1 and ARG2 + + ARG1 * ARG2 arithmetic product of ARG1 and ARG2 + ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2 + ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2 + + STRING : REGEXP anchored pattern match of REGEXP in STRING + + match STRING REGEXP same as STRING : REGEXP + substr STRING POS LENGTH substring of STRING, POS counted from 1 + index STRING CHARS index in STRING where any CHARS is found, or 0 + length STRING length of STRING + + TOKEN interpret TOKEN as a string, even if it is a + keyword like 'match' or an operator like '/' + + ( EXPRESSION ) value of EXPRESSION + +Beware that many operators need to be escaped or quoted for shells. +Comparisons are arithmetic if both ARGs are numbers, else lexicographical. +Pattern matches return the string matched between \( and \) or null; if +\( and \) are not used, they return the number of characters matched or 0. + +Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null +or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred. + +Environment variables: + * EXPR_DEBUG_TOKENS=1 dump expression's tokens + * EXPR_DEBUG_RPN=1 dump expression represented in reverse polish notation + * EXPR_DEBUG_SYA_STEP=1 dump each parser step + * EXPR_DEBUG_AST=1 dump expression represented abstract syntax tree" \ No newline at end of file diff --git a/src/uu/expr/src/expr.rs b/src/uu/expr/src/expr.rs index 9b4ec0b19..508359e52 100644 --- a/src/uu/expr/src/expr.rs +++ b/src/uu/expr/src/expr.rs @@ -5,29 +5,47 @@ //* For the full copyright and license information, please view the LICENSE //* file that was distributed with this source code. -use clap::{crate_version, Arg, Command}; -use uucore::error::{UResult, USimpleError}; +use clap::{crate_version, Arg, ArgAction, Command}; +use uucore::{ + error::{UResult, USimpleError}, + format_usage, help_section, help_usage, +}; mod syntax_tree; mod tokens; -const VERSION: &str = "version"; -const HELP: &str = "help"; -static USAGE: &str = r#"Print the value of EXPRESSION to standard output - expr [EXPRESSION] - expr [OPTIONS]"#; +mod options { + pub const VERSION: &str = "version"; + pub const HELP: &str = "help"; + pub const EXPRESSION: &str = "expression"; +} -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) - .override_usage(USAGE) + .about(help_section!("about", "expr.md")) + .override_usage(format_usage(help_usage!("expr.md"))) + .after_help(help_section!("after help", "expr.md")) .infer_long_args(true) + .disable_help_flag(true) + .disable_version_flag(true) .arg( - Arg::new(VERSION) - .long(VERSION) - .help("output version information and exit"), + Arg::new(options::VERSION) + .long(options::VERSION) + .help("output version information and exit") + .action(ArgAction::Version), + ) + .arg( + Arg::new(options::HELP) + .long(options::HELP) + .help("display this help and exit") + .action(ArgAction::Help), + ) + .arg( + Arg::new(options::EXPRESSION) + .action(ArgAction::Append) + .allow_hyphen_values(true), ) - .arg(Arg::new(HELP).long(HELP).help("display this help and exit")) } #[uucore::main] @@ -36,20 +54,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // For expr utility we do not want getopts. // The following usage should work without escaping hyphens: `expr -15 = 1 + 2 \* \( 3 - -4 \)` + let matches = uu_app().try_get_matches_from(args)?; + let token_strings = matches + .get_many::(options::EXPRESSION) + .map(|v| v.into_iter().map(|s| s.as_ref()).collect::>()) + .unwrap_or_default(); - if maybe_handle_help_or_version(&args) { - Ok(()) - } else { - let token_strings = args[1..].to_vec(); - - match process_expr(&token_strings) { - Ok(expr_result) => print_expr_ok(&expr_result), - Err(expr_error) => Err(USimpleError::new(2, &expr_error)), - } + match process_expr(&token_strings[..]) { + Ok(expr_result) => print_expr_ok(&expr_result), + Err(expr_error) => Err(USimpleError::new(2, &expr_error)), } } -fn process_expr(token_strings: &[String]) -> Result { +fn process_expr(token_strings: &[&str]) -> Result { let maybe_tokens = tokens::strings_to_tokens(token_strings); let maybe_ast = syntax_tree::tokens_to_ast(maybe_tokens); evaluate_ast(maybe_ast) @@ -67,80 +84,3 @@ fn print_expr_ok(expr_result: &str) -> UResult<()> { fn evaluate_ast(maybe_ast: Result, String>) -> Result { maybe_ast.and_then(|ast| ast.evaluate()) } - -fn maybe_handle_help_or_version(args: &[String]) -> bool { - if args.len() == 2 { - if args[1] == "--help" { - print_help(); - true - } else if args[1] == "--version" { - print_version(); - true - } else { - false - } - } else { - false - } -} - -fn print_help() { - //! The following is taken from GNU coreutils' "expr --help" output. - println!( - r#"Usage: expr EXPRESSION - or: expr OPTION - - --help display this help and exit - --version output version information and exit - -Print the value of EXPRESSION to standard output. A blank line below -separates increasing precedence groups. EXPRESSION may be: - - ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2 - - ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0 - - ARG1 < ARG2 ARG1 is less than ARG2 - ARG1 <= ARG2 ARG1 is less than or equal to ARG2 - ARG1 = ARG2 ARG1 is equal to ARG2 - ARG1 != ARG2 ARG1 is unequal to ARG2 - ARG1 >= ARG2 ARG1 is greater than or equal to ARG2 - ARG1 > ARG2 ARG1 is greater than ARG2 - - ARG1 + ARG2 arithmetic sum of ARG1 and ARG2 - ARG1 - ARG2 arithmetic difference of ARG1 and ARG2 - - ARG1 * ARG2 arithmetic product of ARG1 and ARG2 - ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2 - ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2 - - STRING : REGEXP anchored pattern match of REGEXP in STRING - - match STRING REGEXP same as STRING : REGEXP - substr STRING POS LENGTH substring of STRING, POS counted from 1 - index STRING CHARS index in STRING where any CHARS is found, or 0 - length STRING length of STRING - + TOKEN interpret TOKEN as a string, even if it is a - keyword like 'match' or an operator like '/' - - ( EXPRESSION ) value of EXPRESSION - -Beware that many operators need to be escaped or quoted for shells. -Comparisons are arithmetic if both ARGs are numbers, else lexicographical. -Pattern matches return the string matched between \( and \) or null; if -\( and \) are not used, they return the number of characters matched or 0. - -Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null -or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred. - -Environment variables: - * EXPR_DEBUG_TOKENS=1 dump expression's tokens - * EXPR_DEBUG_RPN=1 dump expression represented in reverse polish notation - * EXPR_DEBUG_SYA_STEP=1 dump each parser step - * EXPR_DEBUG_AST=1 dump expression represented abstract syntax tree"# - ); -} - -fn print_version() { - println!("{} {}", uucore::util_name(), crate_version!()); -} diff --git a/src/uu/expr/src/tokens.rs b/src/uu/expr/src/tokens.rs index a0365898d..6ff930f81 100644 --- a/src/uu/expr/src/tokens.rs +++ b/src/uu/expr/src/tokens.rs @@ -69,12 +69,12 @@ impl Token { } } -pub fn strings_to_tokens(strings: &[String]) -> Result, String> { +pub fn strings_to_tokens(strings: &[&str]) -> Result, String> { let mut tokens_acc = Vec::with_capacity(strings.len()); let mut tok_idx = 1; for s in strings { - let token_if_not_escaped = match s.as_ref() { + let token_if_not_escaped = match *s { "(" => Token::ParOpen, ")" => Token::ParClose, @@ -94,15 +94,15 @@ pub fn strings_to_tokens(strings: &[String]) -> Result, Stri "match" | "index" => Token::PrefixOp { arity: 2, - value: s.clone(), + value: s.to_string(), }, "substr" => Token::PrefixOp { arity: 3, - value: s.clone(), + value: s.to_string(), }, "length" => Token::PrefixOp { arity: 1, - value: s.clone(), + value: s.to_string(), }, _ => Token::new_value(s), diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index 85e31027b..b5b091b45 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" num-traits = "0.2.15" # used in src/numerics.rs, which is included by build.rs [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } coz = { version = "0.1.3", optional = true } num-traits = "0.2.15" # Needs at least version 0.2.15 for "OverflowingAdd" rand = { version = "0.8", features = ["small_rng"] } diff --git a/src/uu/factor/src/cli.rs b/src/uu/factor/src/cli.rs index 3c345ab48..1bf764ca6 100644 --- a/src/uu/factor/src/cli.rs +++ b/src/uu/factor/src/cli.rs @@ -15,7 +15,7 @@ use std::io::BufRead; use std::io::{self, stdin, stdout, Write}; mod factor; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; pub use factor::*; use uucore::display::Quotable; use uucore::error::UResult; @@ -78,10 +78,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) .infer_long_args(true) - .arg(Arg::new(options::NUMBER).multiple_occurrences(true)) + .arg(Arg::new(options::NUMBER).action(ArgAction::Append)) } diff --git a/src/uu/false/Cargo.toml b/src/uu/false/Cargo.toml index 706769af6..1bc1f848e 100644 --- a/src/uu/false/Cargo.toml +++ b/src/uu/false/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/false.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/false/src/false.rs b/src/uu/false/src/false.rs index 4b8ef36e2..3a74142e0 100644 --- a/src/uu/false/src/false.rs +++ b/src/uu/false/src/false.rs @@ -33,8 +33,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if let Err(e) = command.try_get_matches_from_mut(args) { let error = match e.kind() { - clap::ErrorKind::DisplayHelp => command.print_help(), - clap::ErrorKind::DisplayVersion => { + clap::error::ErrorKind::DisplayHelp => command.print_help(), + clap::error::ErrorKind::DisplayVersion => { writeln!(std::io::stdout(), "{}", command.render_version()) } _ => Ok(()), @@ -50,7 +50,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(clap::crate_version!()) .about(ABOUT) diff --git a/src/uu/fmt/Cargo.toml b/src/uu/fmt/Cargo.toml index af6d44b1a..0e0445853 100644 --- a/src/uu/fmt/Cargo.toml +++ b/src/uu/fmt/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/fmt.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } unicode-width = "0.1.5" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/fmt/src/fmt.rs b/src/uu/fmt/src/fmt.rs index 5aa6d04c6..01f859131 100644 --- a/src/uu/fmt/src/fmt.rs +++ b/src/uu/fmt/src/fmt.rs @@ -10,7 +10,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::cmp; use std::fs::File; use std::io::{stdin, stdout, Write}; @@ -92,15 +92,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { tabwidth: 8, }; - fmt_opts.tagged = matches.contains_id(OPT_TAGGED_PARAGRAPH); - if matches.contains_id(OPT_CROWN_MARGIN) { + fmt_opts.tagged = matches.get_flag(OPT_TAGGED_PARAGRAPH); + if matches.get_flag(OPT_CROWN_MARGIN) { fmt_opts.crown = true; fmt_opts.tagged = false; } - fmt_opts.mail = matches.contains_id(OPT_PRESERVE_HEADERS); - fmt_opts.uniform = matches.contains_id(OPT_UNIFORM_SPACING); - fmt_opts.quick = matches.contains_id(OPT_QUICK); - if matches.contains_id(OPT_SPLIT_ONLY) { + fmt_opts.mail = matches.get_flag(OPT_PRESERVE_HEADERS); + fmt_opts.uniform = matches.get_flag(OPT_UNIFORM_SPACING); + fmt_opts.quick = matches.get_flag(OPT_QUICK); + if matches.get_flag(OPT_SPLIT_ONLY) { fmt_opts.split_only = true; fmt_opts.crown = false; fmt_opts.tagged = false; @@ -150,7 +150,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )); } }; - if !matches.contains_id(OPT_WIDTH) { + if !matches.get_flag(OPT_WIDTH) { fmt_opts.width = cmp::max(fmt_opts.goal * 100 / 94, fmt_opts.goal + 3); } else if fmt_opts.goal > fmt_opts.width { return Err(USimpleError::new(1, "GOAL cannot be greater than WIDTH.")); @@ -218,7 +218,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -233,7 +233,8 @@ pub fn uu_app<'a>() -> Command<'a> { may have different indentations, in which \ case the first line's indentation is preserved, \ and each subsequent line's indentation matches the second line.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_TAGGED_PARAGRAPH) @@ -242,7 +243,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Like -c, except that the first and second line of a paragraph *must* \ have different indentation or they are treated as separate paragraphs.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_PRESERVE_HEADERS) @@ -251,13 +253,15 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Attempt to detect and preserve mail headers in the input. \ Be careful when combining this flag with -p.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_SPLIT_ONLY) .short('s') .long("split-only") - .help("Split lines only, do not reflow."), + .help("Split lines only, do not reflow.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_UNIFORM_SPACING) @@ -269,7 +273,8 @@ pub fn uu_app<'a>() -> Command<'a> { Sentence breaks in the input are detected as [?!.] \ followed by two spaces or a newline; other punctuation \ is not interpreted as a sentence break.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_PREFIX) @@ -301,7 +306,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "PREFIX must match at the \ beginning of the line with no preceding whitespace.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_EXACT_SKIP_PREFIX) @@ -310,7 +316,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "PSKIP must match at the \ beginning of the line with no preceding whitespace.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_WIDTH) @@ -326,10 +333,16 @@ pub fn uu_app<'a>() -> Command<'a> { .help("Goal width, default ~0.94*WIDTH. Must be less than WIDTH.") .value_name("GOAL"), ) - .arg(Arg::new(OPT_QUICK).short('q').long("quick").help( - "Break lines more quickly at the \ + .arg( + Arg::new(OPT_QUICK) + .short('q') + .long("quick") + .help( + "Break lines more quickly at the \ expense of a potentially more ragged appearance.", - )) + ) + .action(ArgAction::SetTrue), + ) .arg( Arg::new(OPT_TAB_WIDTH) .short('T') @@ -343,8 +356,7 @@ pub fn uu_app<'a>() -> Command<'a> { ) .arg( Arg::new(ARG_FILES) - .multiple_occurrences(true) - .takes_value(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::FilePath), ) } diff --git a/src/uu/fold/Cargo.toml b/src/uu/fold/Cargo.toml index ef4d80cda..e0f91af8c 100644 --- a/src/uu/fold/Cargo.toml +++ b/src/uu/fold/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/fold.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/fold/src/fold.rs b/src/uu/fold/src/fold.rs index d229fe690..6761e4522 100644 --- a/src/uu/fold/src/fold.rs +++ b/src/uu/fold/src/fold.rs @@ -7,7 +7,7 @@ // spell-checker:ignore (ToDOs) ncount routput -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::fs::File; use std::io::{stdin, BufRead, BufReader, Read}; use std::path::Path; @@ -36,8 +36,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let (args, obs_width) = handle_obsolete(&args[..]); let matches = uu_app().try_get_matches_from(args)?; - let bytes = matches.contains_id(options::BYTES); - let spaces = matches.contains_id(options::SPACES); + let bytes = matches.get_flag(options::BYTES); + let spaces = matches.get_flag(options::SPACES); let poss_width = match matches.get_one::(options::WIDTH) { Some(v) => Some(v.to_owned()), None => obs_width, @@ -61,7 +61,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { fold(&files, bytes, spaces, width) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .name(NAME) .version(crate_version!()) @@ -76,14 +76,14 @@ pub fn uu_app<'a>() -> Command<'a> { "count using bytes rather than columns (meaning control characters \ such as newline are not treated specially)", ) - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SPACES) .long(options::SPACES) .short('s') .help("break lines at word boundaries rather than a hard cut-off") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::WIDTH) @@ -91,13 +91,12 @@ pub fn uu_app<'a>() -> Command<'a> { .short('w') .help("set WIDTH as the maximum line width rather than 80") .value_name("WIDTH") - .allow_hyphen_values(true) - .takes_value(true), + .allow_hyphen_values(true), ) .arg( Arg::new(options::FILE) .hide(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::FilePath), ) } diff --git a/src/uu/groups/Cargo.toml b/src/uu/groups/Cargo.toml index f16cf0880..a1bacbb47 100644 --- a/src/uu/groups/Cargo.toml +++ b/src/uu/groups/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/groups.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "process"] } [[bin]] diff --git a/src/uu/groups/src/groups.rs b/src/uu/groups/src/groups.rs index f1377234d..1dd692ccd 100644 --- a/src/uu/groups/src/groups.rs +++ b/src/uu/groups/src/groups.rs @@ -26,7 +26,7 @@ use uucore::{ format_usage, }; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; mod options { pub const USERS: &str = "USERNAME"; @@ -102,7 +102,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -110,8 +110,7 @@ pub fn uu_app<'a>() -> Command<'a> { .infer_long_args(true) .arg( Arg::new(options::USERS) - .multiple_occurrences(true) - .takes_value(true) + .action(ArgAction::Append) .value_name(options::USERS) .value_hint(clap::ValueHint::Username), ) diff --git a/src/uu/hashsum/Cargo.toml b/src/uu/hashsum/Cargo.toml index 312ac2cd9..23e2bba0d 100644 --- a/src/uu/hashsum/Cargo.toml +++ b/src/uu/hashsum/Cargo.toml @@ -16,7 +16,7 @@ path = "src/hashsum.rs" [dependencies] digest = "0.10.5" -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } hex = "0.4.3" memchr = "2" md-5 = "0.10.5" diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 4d5baea12..e2e904343 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -21,6 +21,7 @@ use self::digest::Digest; use self::digest::DigestWriter; use clap::builder::ValueParser; +use clap::ArgAction; use clap::{Arg, ArgMatches, Command}; use hex::encode; use md5::Md5; @@ -80,34 +81,31 @@ fn detect_algo( Box::new(blake3::Hasher::new()) as Box, 256, ), - "sha3sum" => match matches.get_one::("bits") { - Some(bits_str) => match (bits_str).parse::() { - Ok(224) => ( - "SHA3-224", - Box::new(Sha3_224::new()) as Box, - 224, - ), - Ok(256) => ( - "SHA3-256", - Box::new(Sha3_256::new()) as Box, - 256, - ), - Ok(384) => ( - "SHA3-384", - Box::new(Sha3_384::new()) as Box, - 384, - ), - Ok(512) => ( - "SHA3-512", - Box::new(Sha3_512::new()) as Box, - 512, - ), - Ok(_) => crash!( - 1, - "Invalid output size for SHA3 (expected 224, 256, 384, or 512)" - ), - Err(err) => crash!(1, "{}", err), - }, + "sha3sum" => match matches.get_one::("bits") { + Some(224) => ( + "SHA3-224", + Box::new(Sha3_224::new()) as Box, + 224, + ), + Some(256) => ( + "SHA3-256", + Box::new(Sha3_256::new()) as Box, + 256, + ), + Some(384) => ( + "SHA3-384", + Box::new(Sha3_384::new()) as Box, + 384, + ), + Some(512) => ( + "SHA3-512", + Box::new(Sha3_512::new()) as Box, + 512, + ), + Some(_) => crash!( + 1, + "Invalid output size for SHA3 (expected 224, 256, 384, or 512)" + ), None => crash!(1, "--bits required for SHA3"), }, "sha3-224sum" => ( @@ -130,26 +128,20 @@ fn detect_algo( Box::new(Sha3_512::new()) as Box, 512, ), - "shake128sum" => match matches.get_one::("bits") { - Some(bits_str) => match (bits_str).parse::() { - Ok(bits) => ( - "SHAKE128", - Box::new(Shake128::new()) as Box, - bits, - ), - Err(err) => crash!(1, "{}", err), - }, + "shake128sum" => match matches.get_one::("bits") { + Some(bits) => ( + "SHAKE128", + Box::new(Shake128::new()) as Box, + *bits, + ), None => crash!(1, "--bits required for SHAKE-128"), }, - "shake256sum" => match matches.get_one::("bits") { - Some(bits_str) => match (bits_str).parse::() { - Ok(bits) => ( - "SHAKE256", - Box::new(Shake256::new()) as Box, - bits, - ), - Err(err) => crash!(1, "{}", err), - }, + "shake256sum" => match matches.get_one::("bits") { + Some(bits) => ( + "SHAKE256", + Box::new(Shake256::new()) as Box, + *bits, + ), None => crash!(1, "--bits required for SHAKE-256"), }, _ => { @@ -162,89 +154,80 @@ fn detect_algo( alg = Some(val); output_bits = bits; }; - if matches.contains_id("md5") { + if matches.get_flag("md5") { set_or_crash("MD5", Box::new(Md5::new()), 128); } - if matches.contains_id("sha1") { + if matches.get_flag("sha1") { set_or_crash("SHA1", Box::new(Sha1::new()), 160); } - if matches.contains_id("sha224") { + if matches.get_flag("sha224") { set_or_crash("SHA224", Box::new(Sha224::new()), 224); } - if matches.contains_id("sha256") { + if matches.get_flag("sha256") { set_or_crash("SHA256", Box::new(Sha256::new()), 256); } - if matches.contains_id("sha384") { + if matches.get_flag("sha384") { set_or_crash("SHA384", Box::new(Sha384::new()), 384); } - if matches.contains_id("sha512") { + if matches.get_flag("sha512") { set_or_crash("SHA512", Box::new(Sha512::new()), 512); } - if matches.contains_id("b2sum") { + if matches.get_flag("b2sum") { set_or_crash("BLAKE2", Box::new(blake2b_simd::State::new()), 512); } - if matches.contains_id("b3sum") { + if matches.get_flag("b3sum") { set_or_crash("BLAKE3", Box::new(blake3::Hasher::new()), 256); } - if matches.contains_id("sha3") { - match matches.get_one::("bits") { - Some(bits_str) => match (bits_str).parse::() { - Ok(224) => set_or_crash( - "SHA3-224", - Box::new(Sha3_224::new()) as Box, - 224, - ), - Ok(256) => set_or_crash( - "SHA3-256", - Box::new(Sha3_256::new()) as Box, - 256, - ), - Ok(384) => set_or_crash( - "SHA3-384", - Box::new(Sha3_384::new()) as Box, - 384, - ), - Ok(512) => set_or_crash( - "SHA3-512", - Box::new(Sha3_512::new()) as Box, - 512, - ), - Ok(_) => crash!( - 1, - "Invalid output size for SHA3 (expected 224, 256, 384, or 512)" - ), - Err(err) => crash!(1, "{}", err), - }, + if matches.get_flag("sha3") { + match matches.get_one::("bits") { + Some(224) => set_or_crash( + "SHA3-224", + Box::new(Sha3_224::new()) as Box, + 224, + ), + Some(256) => set_or_crash( + "SHA3-256", + Box::new(Sha3_256::new()) as Box, + 256, + ), + Some(384) => set_or_crash( + "SHA3-384", + Box::new(Sha3_384::new()) as Box, + 384, + ), + Some(512) => set_or_crash( + "SHA3-512", + Box::new(Sha3_512::new()) as Box, + 512, + ), + Some(_) => crash!( + 1, + "Invalid output size for SHA3 (expected 224, 256, 384, or 512)" + ), None => crash!(1, "--bits required for SHA3"), } } - if matches.contains_id("sha3-224") { + if matches.get_flag("sha3-224") { set_or_crash("SHA3-224", Box::new(Sha3_224::new()), 224); } - if matches.contains_id("sha3-256") { + if matches.get_flag("sha3-256") { set_or_crash("SHA3-256", Box::new(Sha3_256::new()), 256); } - if matches.contains_id("sha3-384") { + if matches.get_flag("sha3-384") { set_or_crash("SHA3-384", Box::new(Sha3_384::new()), 384); } - if matches.contains_id("sha3-512") { + if matches.get_flag("sha3-512") { set_or_crash("SHA3-512", Box::new(Sha3_512::new()), 512); } - if matches.contains_id("shake128") { - match matches.get_one::("bits") { - Some(bits_str) => match (bits_str).parse::() { - Ok(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), bits), - Err(err) => crash!(1, "{}", err), - }, + if matches.get_flag("shake128") { + match matches.get_one::("bits") { + Some(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), *bits), None => crash!(1, "--bits required for SHAKE-128"), } } - if matches.contains_id("shake256") { - match matches.get_one::("bits") { - Some(bits_str) => match (bits_str).parse::() { - Ok(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), bits), - Err(err) => crash!(1, "{}", err), - }, + if matches.get_flag("shake256") { + match matches.get_one::("bits") { + Some(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), *bits), None => crash!(1, "--bits required for SHAKE-256"), } } @@ -260,10 +243,6 @@ fn parse_bit_num(arg: &str) -> Result { arg.parse() } -fn is_valid_bit_num(arg: &str) -> Result<(), String> { - parse_bit_num(arg).map(|_| ()).map_err(|e| format!("{}", e)) -} - #[uucore::main] pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { // if there is no program name for some reason, default to "hashsum" @@ -288,24 +267,24 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { let (name, algo, bits) = detect_algo(&binary_name, &matches); - let binary = if matches.contains_id("binary") { + let binary = if matches.get_flag("binary") { true - } else if matches.contains_id("text") { + } else if matches.get_flag("text") { false } else { binary_flag_default }; - let check = matches.contains_id("check"); - let tag = matches.contains_id("tag"); + let check = matches.get_flag("check"); + let tag = matches.get_flag("tag"); let nonames = if binary_name == "b3sum" { - matches.contains_id("no-names") + matches.get_flag("no-names") } else { false }; - let status = matches.contains_id("status"); - let quiet = matches.contains_id("quiet") || status; - let strict = matches.contains_id("strict"); - let warn = matches.contains_id("warn") && !status; + let status = matches.get_flag("status"); + let quiet = matches.get_flag("quiet") || status; + let strict = matches.get_flag("strict"); + let warn = matches.get_flag("warn") && !status; let opts = Options { algoname: name, @@ -327,7 +306,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { } } -pub fn uu_app_common<'a>() -> Command<'a> { +pub fn uu_app_common() -> Command { #[cfg(windows)] const BINARY_HELP: &str = "read in binary mode (default)"; #[cfg(not(windows))] @@ -344,60 +323,68 @@ pub fn uu_app_common<'a>() -> Command<'a> { Arg::new("binary") .short('b') .long("binary") - .help(BINARY_HELP), + .help(BINARY_HELP) + .action(ArgAction::SetTrue), ) .arg( Arg::new("check") .short('c') .long("check") - .help("read hashsums from the FILEs and check them"), + .help("read hashsums from the FILEs and check them") + .action(ArgAction::SetTrue), ) .arg( Arg::new("tag") .long("tag") - .help("create a BSD-style checksum"), + .help("create a BSD-style checksum") + .action(ArgAction::SetTrue), ) .arg( Arg::new("text") .short('t') .long("text") .help(TEXT_HELP) - .conflicts_with("binary"), + .conflicts_with("binary") + .action(ArgAction::SetTrue), ) .arg( Arg::new("quiet") .short('q') .long("quiet") - .help("don't print OK for each successfully verified file"), + .help("don't print OK for each successfully verified file") + .action(ArgAction::SetTrue), ) .arg( Arg::new("status") .short('s') .long("status") - .help("don't output anything, status code shows success"), + .help("don't output anything, status code shows success") + .action(ArgAction::SetTrue), ) .arg( Arg::new("strict") .long("strict") - .help("exit non-zero for improperly formatted checksum lines"), + .help("exit non-zero for improperly formatted checksum lines") + .action(ArgAction::SetTrue), ) .arg( Arg::new("warn") .short('w') .long("warn") - .help("warn about improperly formatted checksum lines"), + .help("warn about improperly formatted checksum lines") + .action(ArgAction::SetTrue), ) .arg( Arg::new("FILE") .index(1) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_name("FILE") .value_hint(clap::ValueHint::FilePath) .value_parser(ValueParser::os_string()), ) } -pub fn uu_app_b3sum<'a>() -> Command<'a> { +pub fn uu_app_b3sum() -> Command { uu_app_b3sum_opts(uu_app_common()) } @@ -405,11 +392,12 @@ fn uu_app_b3sum_opts(command: Command) -> Command { command.arg( Arg::new("no-names") .long("no-names") - .help("Omits filenames in the output (option not present in GNU/Coreutils)"), + .help("Omits filenames in the output (option not present in GNU/Coreutils)") + .action(ArgAction::SetTrue), ) } -pub fn uu_app_bits<'a>() -> Command<'a> { +pub fn uu_app_bits() -> Command { uu_app_opt_bits(uu_app_common()) } @@ -419,14 +407,13 @@ fn uu_app_opt_bits(command: Command) -> Command { Arg::new("bits") .long("bits") .help("set the size of the output (only for SHAKE)") - .takes_value(true) .value_name("BITS") // XXX: should we actually use validators? they're not particularly efficient - .validator(is_valid_bit_num), + .value_parser(parse_bit_num), ) } -pub fn uu_app_custom<'a>() -> Command<'a> { +pub fn uu_app_custom() -> Command { let mut command = uu_app_b3sum_opts(uu_app_opt_bits(uu_app_common())); let algorithms = &[ ("md5", "work with MD5"), @@ -453,14 +440,19 @@ pub fn uu_app_custom<'a>() -> Command<'a> { ]; for (name, desc) in algorithms { - command = command.arg(Arg::new(*name).long(name).help(*desc)); + command = command.arg( + Arg::new(*name) + .long(name) + .help(*desc) + .action(ArgAction::SetTrue), + ); } command } // hashsum is handled differently in build.rs, therefore this is not the same // as in other utilities. -fn uu_app<'a>(binary_name: &str) -> Command<'a> { +fn uu_app(binary_name: &str) -> Command { match binary_name { // These all support the same options. "md5sum" | "sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" => { diff --git a/src/uu/head/Cargo.toml b/src/uu/head/Cargo.toml index 82a7d8b24..8c9a6f884 100644 --- a/src/uu/head/Cargo.toml +++ b/src/uu/head/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/head.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } memchr = "2" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] } diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index 6ba36659a..a01fe94f7 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -5,7 +5,7 @@ // spell-checker:ignore (vars) zlines BUFWRITER seekable -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use std::ffi::OsString; use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write}; use uucore::display::Quotable; @@ -41,7 +41,7 @@ mod take; use take::take_all_but; use take::take_lines; -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -52,7 +52,6 @@ pub fn uu_app<'a>() -> Command<'a> { .short('c') .long("bytes") .value_name("[-]NUM") - .takes_value(true) .help( "\ print the first NUM bytes of each file;\n\ @@ -68,7 +67,6 @@ pub fn uu_app<'a>() -> Command<'a> { .short('n') .long("lines") .value_name("[-]NUM") - .takes_value(true) .help( "\ print the first NUM lines instead of the first 10;\n\ @@ -85,31 +83,35 @@ pub fn uu_app<'a>() -> Command<'a> { .long("quiet") .visible_alias("silent") .help("never print headers giving file names") - .overrides_with_all(&[options::VERBOSE_NAME, options::QUIET_NAME]), + .overrides_with_all(&[options::VERBOSE_NAME, options::QUIET_NAME]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::VERBOSE_NAME) .short('v') .long("verbose") .help("always print headers giving file names") - .overrides_with_all(&[options::QUIET_NAME, options::VERBOSE_NAME]), + .overrides_with_all(&[options::QUIET_NAME, options::VERBOSE_NAME]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::PRESUME_INPUT_PIPE) - .long("-presume-input-pipe") + .long("presume-input-pipe") .alias("-presume-input-pipe") - .hide(true), + .hide(true) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ZERO_NAME) .short('z') .long("zero-terminated") .help("line delimiter is NUL, not newline") - .overrides_with(options::ZERO_NAME), + .overrides_with(options::ZERO_NAME) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::FILES_NAME) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::FilePath), ) } @@ -199,10 +201,10 @@ impl HeadOptions { pub fn get_from(matches: &clap::ArgMatches) -> Result { let mut options = Self::default(); - options.quiet = matches.contains_id(options::QUIET_NAME); - options.verbose = matches.contains_id(options::VERBOSE_NAME); - options.zeroed = matches.contains_id(options::ZERO_NAME); - options.presume_input_pipe = matches.contains_id(options::PRESUME_INPUT_PIPE); + options.quiet = matches.get_flag(options::QUIET_NAME); + options.verbose = matches.get_flag(options::VERBOSE_NAME); + options.zeroed = matches.get_flag(options::ZERO_NAME); + options.presume_input_pipe = matches.get_flag(options::PRESUME_INPUT_PIPE); options.mode = Mode::from(matches)?; diff --git a/src/uu/hostid/Cargo.toml b/src/uu/hostid/Cargo.toml index 34a39e800..0938a1bec 100644 --- a/src/uu/hostid/Cargo.toml +++ b/src/uu/hostid/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/hostid.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" } diff --git a/src/uu/hostid/src/hostid.rs b/src/uu/hostid/src/hostid.rs index d555a068f..293a9cacd 100644 --- a/src/uu/hostid/src/hostid.rs +++ b/src/uu/hostid/src/hostid.rs @@ -26,7 +26,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) diff --git a/src/uu/hostname/Cargo.toml b/src/uu/hostname/Cargo.toml index ab34a8314..120440005 100644 --- a/src/uu/hostname/Cargo.toml +++ b/src/uu/hostname/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/hostname.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } hostname = { version = "0.3", features = ["set"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["wide"] } diff --git a/src/uu/hostname/src/hostname.rs b/src/uu/hostname/src/hostname.rs index 9c1157e18..7aec443a9 100644 --- a/src/uu/hostname/src/hostname.rs +++ b/src/uu/hostname/src/hostname.rs @@ -12,7 +12,7 @@ use std::str; use std::{collections::hash_set::HashSet, ffi::OsString}; use clap::builder::ValueParser; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use uucore::{ error::{FromIo, UResult}, @@ -72,7 +72,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!()) .about(ABOUT) @@ -83,28 +83,32 @@ pub fn uu_app<'a>() -> Command<'a> { .short('d') .long("domain") .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) - .help("Display the name of the DNS domain if possible"), + .help("Display the name of the DNS domain if possible") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_IP_ADDRESS) .short('i') .long("ip-address") .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) - .help("Display the network address(es) of the host"), + .help("Display the network address(es) of the host") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_FQDN) .short('f') .long("fqdn") .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) - .help("Display the FQDN (Fully Qualified Domain Name) (default)"), + .help("Display the FQDN (Fully Qualified Domain Name) (default)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_SHORT) .short('s') .long("short") .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) - .help("Display the short hostname (the portion before the first dot) if possible"), + .help("Display the short hostname (the portion before the first dot) if possible") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_HOST) @@ -119,7 +123,7 @@ fn display_hostname(matches: &ArgMatches) -> UResult<()> { .to_string_lossy() .into_owned(); - if matches.contains_id(OPT_IP_ADDRESS) { + if matches.get_flag(OPT_IP_ADDRESS) { // XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later. // This was originally supposed to use std::net::lookup_host, but that seems to be // deprecated. Perhaps we should use the dns-lookup crate? @@ -149,10 +153,10 @@ fn display_hostname(matches: &ArgMatches) -> UResult<()> { Ok(()) } else { - if matches.contains_id(OPT_SHORT) || matches.contains_id(OPT_DOMAIN) { + if matches.get_flag(OPT_SHORT) || matches.get_flag(OPT_DOMAIN) { let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.'); if let Some(ci) = it.next() { - if matches.contains_id(OPT_SHORT) { + if matches.get_flag(OPT_SHORT) { println!("{}", &hostname[0..ci.0]); } else { println!("{}", &hostname[ci.0 + 1..]); diff --git a/src/uu/id/Cargo.toml b/src/uu/id/Cargo.toml index e4f4847b2..0329df212 100644 --- a/src/uu/id/Cargo.toml +++ b/src/uu/id/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/id.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "process"] } selinux = { version="0.3", optional = true } diff --git a/src/uu/id/src/id.rs b/src/uu/id/src/id.rs index 6269166ef..720339545 100644 --- a/src/uu/id/src/id.rs +++ b/src/uu/id/src/id.rs @@ -39,7 +39,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use std::ffi::CStr; use uucore::display::Quotable; use uucore::entries::{self, Group, Locate, Passwd}; @@ -79,15 +79,13 @@ mod options { pub const ARG_USERS: &str = "USER"; } -fn get_description() -> String { - String::from( - "The id utility displays the user and group names and numeric IDs, of the \ - calling process, to the standard output. If the real and effective IDs are \ - different, both are displayed, otherwise only the real ID is displayed.\n\n\ - If a user (login name or user ID) is specified, the user and group IDs of \ - that user are displayed. In this case, the real and effective IDs are \ - assumed to be the same.", - ) +fn get_description() -> &'static str { + "The id utility displays the user and group names and numeric IDs, of the \ + calling process, to the standard output. If the real and effective IDs are \ + different, both are displayed, otherwise only the real ID is displayed.\n\n\ + If a user (login name or user ID) is specified, the user and group IDs of \ + that user are displayed. In this case, the real and effective IDs are \ + assumed to be the same." } struct Ids { @@ -126,10 +124,8 @@ struct State { #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let after_help = get_description(); - let matches = uu_app() - .after_help(&after_help[..]) + .after_help(get_description()) .try_get_matches_from(args)?; let users: Vec = matches @@ -138,13 +134,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .unwrap_or_default(); let mut state = State { - nflag: matches.contains_id(options::OPT_NAME), - uflag: matches.contains_id(options::OPT_EFFECTIVE_USER), - gflag: matches.contains_id(options::OPT_GROUP), - gsflag: matches.contains_id(options::OPT_GROUPS), - rflag: matches.contains_id(options::OPT_REAL_ID), - zflag: matches.contains_id(options::OPT_ZERO), - cflag: matches.contains_id(options::OPT_CONTEXT), + nflag: matches.get_flag(options::OPT_NAME), + uflag: matches.get_flag(options::OPT_EFFECTIVE_USER), + gflag: matches.get_flag(options::OPT_GROUP), + gsflag: matches.get_flag(options::OPT_GROUPS), + rflag: matches.get_flag(options::OPT_REAL_ID), + zflag: matches.get_flag(options::OPT_ZERO), + cflag: matches.get_flag(options::OPT_CONTEXT), selinux_supported: { #[cfg(feature = "selinux")] @@ -239,17 +235,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; // GNU's `id` does not support the flags: -p/-P/-A. - if matches.contains_id(options::OPT_PASSWORD) { + if matches.get_flag(options::OPT_PASSWORD) { // BSD's `id` ignores all but the first specified user pline(possible_pw.as_ref().map(|v| v.uid)); return Ok(()); }; - if matches.contains_id(options::OPT_HUMAN_READABLE) { + if matches.get_flag(options::OPT_HUMAN_READABLE) { // BSD's `id` ignores all but the first specified user pretty(possible_pw); return Ok(()); } - if matches.contains_id(options::OPT_AUDIT) { + if matches.get_flag(options::OPT_AUDIT) { // BSD's `id` ignores specified users auditid(); return Ok(()); @@ -343,7 +339,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -363,21 +359,24 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Display the process audit user ID and other process audit properties,\n\ which requires privilege (not available on Linux).", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_EFFECTIVE_USER) .short('u') .long(options::OPT_EFFECTIVE_USER) .conflicts_with(options::OPT_GROUP) - .help("Display only the effective user ID as a number."), + .help("Display only the effective user ID as a number.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_GROUP) .short('g') .long(options::OPT_GROUP) .conflicts_with(options::OPT_EFFECTIVE_USER) - .help("Display only the effective group ID as a number"), + .help("Display only the effective group ID as a number") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_GROUPS) @@ -394,12 +393,14 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Display only the different group IDs as white-space separated numbers, \ in no particular order.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_HUMAN_READABLE) .short('p') - .help("Make the output human-readable. Each display is on a separate line."), + .help("Make the output human-readable. Each display is on a separate line.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_NAME) @@ -409,12 +410,14 @@ pub fn uu_app<'a>() -> Command<'a> { "Display the name of the user or group ID for the -G, -g and -u options \ instead of the number.\nIf any of the ID numbers cannot be mapped into \ names, the number will be displayed as usual.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_PASSWORD) .short('P') - .help("Display the id as a password file entry."), + .help("Display the id as a password file entry.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_REAL_ID) @@ -423,7 +426,8 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Display the real ID for the -G, -g and -u options instead of \ the effective ID.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_ZERO) @@ -432,19 +436,20 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "delimit entries with NUL characters, not whitespace;\n\ not permitted in default format", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OPT_CONTEXT) .short('Z') .long(options::OPT_CONTEXT) .conflicts_with_all(&[options::OPT_GROUP, options::OPT_EFFECTIVE_USER]) - .help(CONTEXT_HELP_TEXT), + .help(CONTEXT_HELP_TEXT) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ARG_USERS) - .multiple_occurrences(true) - .takes_value(true) + .action(ArgAction::Append) .value_name(options::ARG_USERS) .value_hint(clap::ValueHint::Username), ) diff --git a/src/uu/install/Cargo.toml b/src/uu/install/Cargo.toml index 8fa6ed1ca..8766c3786 100644 --- a/src/uu/install/Cargo.toml +++ b/src/uu/install/Cargo.toml @@ -18,7 +18,7 @@ edition = "2021" path = "src/install.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } filetime = "0.2" file_diff = "1.0.0" libc = ">= 0.2" diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index 2b4089195..a340e413d 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -12,7 +12,7 @@ mod mode; #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use file_diff::diff; use filetime::{set_file_times, FileTime}; use uucore::backup_control::{self, BackupMode}; @@ -188,57 +188,63 @@ 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!()) .about(ABOUT) .override_usage(format_usage(USAGE)) .infer_long_args(true) - .arg( - backup_control::arguments::backup() - ) - .arg( - backup_control::arguments::backup_no_args() - ) + .arg(backup_control::arguments::backup()) + .arg(backup_control::arguments::backup_no_args()) .arg( Arg::new(OPT_IGNORED) - .short('c') - .help("ignored") + .short('c') + .help("ignored") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_COMPARE) - .short('C') - .long(OPT_COMPARE) - .help("compare each pair of source and destination files, and in some cases, do not modify the destination at all") + .short('C') + .long(OPT_COMPARE) + .help( + "compare each pair of source and destination files, and in some cases, \ + do not modify the destination at all", + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_DIRECTORY) .short('d') .long(OPT_DIRECTORY) - .help("treat all arguments as directory names. create all components of the specified directories") + .help( + "treat all arguments as directory names. create all components of \ + the specified directories", + ) + .action(ArgAction::SetTrue), ) - .arg( // TODO implement flag Arg::new(OPT_CREATE_LEADING) .short('D') - .help("create all leading components of DEST except the last, then copy SOURCE to DEST") + .help( + "create all leading components of DEST except the last, then copy \ + SOURCE to DEST", + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_GROUP) .short('g') .long(OPT_GROUP) .help("set group ownership, instead of process's current group") - .value_name("GROUP") - .takes_value(true) + .value_name("GROUP"), ) .arg( Arg::new(OPT_MODE) .short('m') .long(OPT_MODE) .help("set permission mode (as in chmod), instead of rwxr-xr-x") - .value_name("MODE") - .takes_value(true) + .value_name("MODE"), ) .arg( Arg::new(OPT_OWNER) @@ -246,31 +252,33 @@ pub fn uu_app<'a>() -> Command<'a> { .long(OPT_OWNER) .help("set ownership (super-user only)") .value_name("OWNER") - .takes_value(true) - .value_hint(clap::ValueHint::Username) + .value_hint(clap::ValueHint::Username), ) .arg( Arg::new(OPT_PRESERVE_TIMESTAMPS) .short('p') .long(OPT_PRESERVE_TIMESTAMPS) - .help("apply access/modification times of SOURCE files to corresponding destination files") + .help( + "apply access/modification times of SOURCE files to \ + corresponding destination files", + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_STRIP) .short('s') .long(OPT_STRIP) .help("strip symbol tables (no action Windows)") + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_STRIP_PROGRAM) .long(OPT_STRIP_PROGRAM) .help("program used to strip binaries (no action Windows)") .value_name("PROGRAM") - .value_hint(clap::ValueHint::CommandName) - ) - .arg( - backup_control::arguments::suffix() + .value_hint(clap::ValueHint::CommandName), ) + .arg(backup_control::arguments::suffix()) .arg( // TODO implement flag Arg::new(OPT_TARGET_DIRECTORY) @@ -278,7 +286,7 @@ pub fn uu_app<'a>() -> Command<'a> { .long(OPT_TARGET_DIRECTORY) .help("move all SOURCE arguments into DIRECTORY") .value_name("DIRECTORY") - .value_hint(clap::ValueHint::DirPath) + .value_hint(clap::ValueHint::DirPath), ) .arg( // TODO implement flag @@ -286,13 +294,14 @@ pub fn uu_app<'a>() -> Command<'a> { .short('T') .long(OPT_NO_TARGET_DIRECTORY) .help("(unimplemented) treat DEST as a normal file") - + .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_VERBOSE) - .short('v') - .long(OPT_VERBOSE) - .help("explain what is being done") + .short('v') + .long(OPT_VERBOSE) + .help("explain what is being done") + .action(ArgAction::SetTrue), ) .arg( // TODO implement flag @@ -300,6 +309,7 @@ pub fn uu_app<'a>() -> Command<'a> { .short('P') .long(OPT_PRESERVE_CONTEXT) .help("(unimplemented) preserve security context") + .action(ArgAction::SetTrue), ) .arg( // TODO implement flag @@ -308,13 +318,13 @@ pub fn uu_app<'a>() -> Command<'a> { .long(OPT_CONTEXT) .help("(unimplemented) set security context of files and directories") .value_name("CONTEXT") + .action(ArgAction::SetTrue), ) .arg( Arg::new(ARG_FILES) - .multiple_occurrences(true) - .takes_value(true) - .min_values(1) - .value_hint(clap::ValueHint::AnyPath) + .action(ArgAction::Append) + .num_args(1..) + .value_hint(clap::ValueHint::AnyPath), ) } @@ -328,11 +338,11 @@ pub fn uu_app<'a>() -> Command<'a> { /// /// fn check_unimplemented(matches: &ArgMatches) -> UResult<()> { - if matches.contains_id(OPT_NO_TARGET_DIRECTORY) { + if matches.get_flag(OPT_NO_TARGET_DIRECTORY) { Err(InstallError::Unimplemented(String::from("--no-target-directory, -T")).into()) - } else if matches.contains_id(OPT_PRESERVE_CONTEXT) { + } else if matches.get_flag(OPT_PRESERVE_CONTEXT) { Err(InstallError::Unimplemented(String::from("--preserve-context, -P")).into()) - } else if matches.contains_id(OPT_CONTEXT) { + } else if matches.get_flag(OPT_CONTEXT) { Err(InstallError::Unimplemented(String::from("--context, -Z")).into()) } else { Ok(()) @@ -348,7 +358,7 @@ fn check_unimplemented(matches: &ArgMatches) -> UResult<()> { /// In event of failure, returns an integer intended as a program return code. /// fn behavior(matches: &ArgMatches) -> UResult { - let main_function = if matches.contains_id(OPT_DIRECTORY) { + let main_function = if matches.get_flag(OPT_DIRECTORY) { MainFunction::Directory } else { MainFunction::Standard @@ -371,9 +381,9 @@ fn behavior(matches: &ArgMatches) -> UResult { .get_one::(OPT_TARGET_DIRECTORY) .map(|d| d.to_owned()); - let preserve_timestamps = matches.contains_id(OPT_PRESERVE_TIMESTAMPS); - let compare = matches.contains_id(OPT_COMPARE); - let strip = matches.contains_id(OPT_STRIP); + let preserve_timestamps = matches.get_flag(OPT_PRESERVE_TIMESTAMPS); + let compare = matches.get_flag(OPT_COMPARE); + let strip = matches.get_flag(OPT_STRIP); if preserve_timestamps && compare { show_error!("Options --compare and --preserve-timestamps are mutually exclusive"); return Err(1.into()); @@ -397,7 +407,7 @@ fn behavior(matches: &ArgMatches) -> UResult { .map(|s| s.as_str()) .unwrap_or("") .to_string(), - verbose: matches.contains_id(OPT_VERBOSE), + verbose: matches.get_flag(OPT_VERBOSE), preserve_timestamps, compare, strip, @@ -407,7 +417,7 @@ fn behavior(matches: &ArgMatches) -> UResult { .map(|s| s.as_str()) .unwrap_or(DEFAULT_STRIP_PROGRAM), ), - create_leading: matches.contains_id(OPT_CREATE_LEADING), + create_leading: matches.get_flag(OPT_CREATE_LEADING), target_dir, }) } diff --git a/src/uu/join/Cargo.toml b/src/uu/join/Cargo.toml index 33b599c8f..0d9e700ac 100644 --- a/src/uu/join/Cargo.toml +++ b/src/uu/join/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/join.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } memchr = "2" diff --git a/src/uu/join/src/join.rs b/src/uu/join/src/join.rs index 53f1efc7c..262b249a4 100644 --- a/src/uu/join/src/join.rs +++ b/src/uu/join/src/join.rs @@ -11,7 +11,7 @@ extern crate uucore; use clap::builder::ValueParser; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use memchr::{memchr3_iter, memchr_iter}; use std::cmp::Ordering; use std::convert::From; @@ -625,7 +625,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } - settings.ignore_case = matches.contains_id("i"); + settings.ignore_case = matches.get_flag("i"); settings.key1 = get_field_number(keys, key1)?; settings.key2 = get_field_number(keys, key2)?; @@ -671,19 +671,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { settings.empty = empty.as_bytes().to_vec(); } - if matches.contains_id("nocheck-order") { + if matches.get_flag("nocheck-order") { settings.check_order = CheckOrder::Disabled; } - if matches.contains_id("check-order") { + if matches.get_flag("check-order") { settings.check_order = CheckOrder::Enabled; } - if matches.contains_id("header") { + if matches.get_flag("header") { settings.headers = true; } - if matches.contains_id("z") { + if matches.get_flag("z") { settings.line_ending = LineEnding::Nul; } @@ -700,7 +700,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(NAME) .version(crate_version!()) .about( @@ -713,8 +713,8 @@ When FILE1 or FILE2 (not both) is -, read standard input.", .arg( Arg::new("a") .short('a') - .multiple_occurrences(true) - .number_of_values(1) + .action(ArgAction::Append) + .num_args(1) .value_parser(["1", "2"]) .value_name("FILENUM") .help( @@ -725,8 +725,8 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2", .arg( Arg::new("v") .short('v') - .multiple_occurrences(true) - .number_of_values(1) + .action(ArgAction::Append) + .num_args(1) .value_parser(["1", "2"]) .value_name("FILENUM") .help("like -a FILENUM, but suppress joined output lines"), @@ -734,7 +734,6 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2", .arg( Arg::new("e") .short('e') - .takes_value(true) .value_name("EMPTY") .help("replace missing input fields with EMPTY"), ) @@ -742,26 +741,24 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2", Arg::new("i") .short('i') .long("ignore-case") - .help("ignore differences in case when comparing fields"), + .help("ignore differences in case when comparing fields") + .action(ArgAction::SetTrue), ) .arg( Arg::new("j") .short('j') - .takes_value(true) .value_name("FIELD") .help("equivalent to '-1 FIELD -2 FIELD'"), ) .arg( Arg::new("o") .short('o') - .takes_value(true) .value_name("FORMAT") .help("obey FORMAT while constructing output line"), ) .arg( Arg::new("t") .short('t') - .takes_value(true) .value_name("CHAR") .value_parser(ValueParser::os_string()) .help("use CHAR as input and output field separator"), @@ -769,35 +766,45 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2", .arg( Arg::new("1") .short('1') - .takes_value(true) .value_name("FIELD") .help("join on this FIELD of file 1"), ) .arg( Arg::new("2") .short('2') - .takes_value(true) .value_name("FIELD") .help("join on this FIELD of file 2"), ) - .arg(Arg::new("check-order").long("check-order").help( - "check that the input is correctly sorted, \ + .arg( + Arg::new("check-order") + .long("check-order") + .help( + "check that the input is correctly sorted, \ even if all input lines are pairable", - )) + ) + .action(ArgAction::SetTrue), + ) .arg( Arg::new("nocheck-order") .long("nocheck-order") - .help("do not check that the input is correctly sorted"), + .help("do not check that the input is correctly sorted") + .action(ArgAction::SetTrue), ) - .arg(Arg::new("header").long("header").help( - "treat the first line in each file as field headers, \ + .arg( + Arg::new("header") + .long("header") + .help( + "treat the first line in each file as field headers, \ print them without trying to pair them", - )) + ) + .action(ArgAction::SetTrue), + ) .arg( Arg::new("z") .short('z') .long("zero-terminated") - .help("line delimiter is NUL, not newline"), + .help("line delimiter is NUL, not newline") + .action(ArgAction::SetTrue), ) .arg( Arg::new("file1") diff --git a/src/uu/kill/Cargo.toml b/src/uu/kill/Cargo.toml index 8db4d8144..cc8d960a4 100644 --- a/src/uu/kill/Cargo.toml +++ b/src/uu/kill/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/kill.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } nix = { version = "0.25", features = ["signal"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["signals"] } diff --git a/src/uu/kill/src/kill.rs b/src/uu/kill/src/kill.rs index 6dadc0ba5..8944bd4e8 100644 --- a/src/uu/kill/src/kill.rs +++ b/src/uu/kill/src/kill.rs @@ -10,7 +10,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use nix::sys::signal::{self, Signal}; use nix::unistd::Pid; use std::io::Error; @@ -43,9 +43,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; - let mode = if matches.contains_id(options::TABLE) { + let mode = if matches.get_flag(options::TABLE) { Mode::Table - } else if matches.contains_id(options::LIST) { + } else if matches.get_flag(options::LIST) { Mode::List } else { Mode::Kill @@ -80,7 +80,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!()) .about(ABOUT) @@ -92,26 +92,28 @@ pub fn uu_app<'a>() -> Command<'a> { .short('l') .long(options::LIST) .help("Lists signals") - .conflicts_with(options::TABLE), + .conflicts_with(options::TABLE) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::TABLE) .short('t') .short_alias('L') .long(options::TABLE) - .help("Lists table of signals"), + .help("Lists table of signals") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SIGNAL) .short('s') .long(options::SIGNAL) - .help("Sends given signal") - .takes_value(true), + .value_name("signal") + .help("Sends given signal instead of SIGTERM"), ) .arg( Arg::new(options::PIDS_OR_SIGNALS) .hide(true) - .multiple_occurrences(true), + .action(ArgAction::Append), ) } diff --git a/src/uu/link/Cargo.toml b/src/uu/link/Cargo.toml index 958adc998..6b4e218da 100644 --- a/src/uu/link/Cargo.toml +++ b/src/uu/link/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/link.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/link/src/link.rs b/src/uu/link/src/link.rs index ba754007f..80b2b1f9b 100644 --- a/src/uu/link/src/link.rs +++ b/src/uu/link/src/link.rs @@ -35,7 +35,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map_err_context(|| format!("cannot create link {} to {}", new.quote(), old.quote())) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -45,9 +45,7 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::FILES) .hide(true) .required(true) - .min_values(2) - .max_values(2) - .takes_value(true) + .num_args(2) .value_hint(clap::ValueHint::AnyPath) .value_parser(ValueParser::os_string()), ) diff --git a/src/uu/ln/Cargo.toml b/src/uu/ln/Cargo.toml index 92da57f80..33a300ee1 100644 --- a/src/uu/ln/Cargo.toml +++ b/src/uu/ln/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/ln.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } [[bin]] diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index a227eb68e..6f179f797 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -10,7 +10,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use uucore::display::Quotable; use uucore::error::{FromIo, UError, UResult}; use uucore::format_usage; @@ -128,15 +128,14 @@ static ARG_FILES: &str = "files"; #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let long_usage = long_usage(); + // clap requires a 'static string + let long_usage = format!( + "{}\n{}", + long_usage(), + backup_control::BACKUP_CONTROL_LONG_HELP + ); - let matches = uu_app() - .after_help(&*format!( - "{}\n{}", - long_usage, - backup_control::BACKUP_CONTROL_LONG_HELP - )) - .try_get_matches_from(args)?; + let matches = uu_app().after_help(long_usage).try_get_matches_from(args)?; /* the list of files */ @@ -146,11 +145,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map(PathBuf::from) .collect(); - let symbolic = matches.contains_id(options::SYMBOLIC); + let symbolic = matches.get_flag(options::SYMBOLIC); - let overwrite_mode = if matches.contains_id(options::FORCE) { + let overwrite_mode = if matches.get_flag(options::FORCE) { OverwriteMode::Force - } else if matches.contains_id(options::INTERACTIVE) { + } else if matches.get_flag(options::INTERACTIVE) { OverwriteMode::Interactive } else { OverwriteMode::NoClobber @@ -160,7 +159,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let backup_suffix = backup_control::determine_backup_suffix(&matches); // When we have "-L" or "-L -P", false otherwise - let logical = matches.contains_id(options::LOGICAL); + let logical = matches.get_flag(options::LOGICAL); let settings = Settings { overwrite: overwrite_mode, @@ -168,19 +167,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { suffix: backup_suffix, symbolic, logical, - relative: matches.contains_id(options::RELATIVE), + relative: matches.get_flag(options::RELATIVE), target_dir: matches .get_one::(options::TARGET_DIRECTORY) .map(String::from), - no_target_dir: matches.contains_id(options::NO_TARGET_DIRECTORY), - no_dereference: matches.contains_id(options::NO_DEREFERENCE), - verbose: matches.contains_id(options::VERBOSE), + no_target_dir: matches.get_flag(options::NO_TARGET_DIRECTORY), + no_dereference: matches.get_flag(options::NO_DEREFERENCE), + verbose: matches.get_flag(options::VERBOSE), }; exec(&paths[..], &settings) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) @@ -198,13 +197,15 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::FORCE) .short('f') .long(options::FORCE) - .help("remove existing destination files"), + .help("remove existing destination files") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::INTERACTIVE) .short('i') .long(options::INTERACTIVE) - .help("prompt whether to remove existing destination files"), + .help("prompt whether to remove existing destination files") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_DEREFERENCE) @@ -213,21 +214,24 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "treat LINK_NAME as a normal file if it is a \ symbolic link to a directory", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::LOGICAL) .short('L') .long(options::LOGICAL) .help("dereference TARGETs that are symbolic links") - .overrides_with(options::PHYSICAL), + .overrides_with(options::PHYSICAL) + .action(ArgAction::SetTrue), ) .arg( // Not implemented yet Arg::new(options::PHYSICAL) .short('P') .long(options::PHYSICAL) - .help("make hard links directly to symbolic links"), + .help("make hard links directly to symbolic links") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SYMBOLIC) @@ -235,7 +239,8 @@ pub fn uu_app<'a>() -> Command<'a> { .long(options::SYMBOLIC) .help("make symbolic links instead of hard links") // override added for https://github.com/uutils/coreutils/issues/2359 - .overrides_with(options::SYMBOLIC), + .overrides_with(options::SYMBOLIC) + .action(ArgAction::SetTrue), ) .arg(backup_control::arguments::suffix()) .arg( @@ -251,28 +256,30 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::NO_TARGET_DIRECTORY) .short('T') .long(options::NO_TARGET_DIRECTORY) - .help("treat LINK_NAME as a normal file always"), + .help("treat LINK_NAME as a normal file always") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::RELATIVE) .short('r') .long(options::RELATIVE) .help("create symbolic links relative to link location") - .requires(options::SYMBOLIC), + .requires(options::SYMBOLIC) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::VERBOSE) .short('v') .long(options::VERBOSE) - .help("print name of each linked file"), + .help("print name of each linked file") + .action(ArgAction::SetTrue), ) .arg( Arg::new(ARG_FILES) - .multiple_occurrences(true) - .takes_value(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath) .required(true) - .min_values(1), + .num_args(1..), ) } diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index 86a5a8ef7..e688346ce 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -16,7 +16,7 @@ path = "src/logname.rs" [dependencies] libc = "0.2.135" -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/logname/src/logname.rs b/src/uu/logname/src/logname.rs index 94d690713..1eba4f34e 100644 --- a/src/uu/logname/src/logname.rs +++ b/src/uu/logname/src/logname.rs @@ -48,7 +48,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .override_usage(uucore::execution_phrase()) diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index 922affea5..6160040ca 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -16,7 +16,7 @@ path = "src/ls.rs" [dependencies] chrono = { version="^0.4.19", default-features=false, features=["std", "alloc", "clock"]} -clap = { version = "3.2", features = ["wrap_help", "cargo", "env"] } +clap = { version = "4.0", features = ["wrap_help", "cargo", "env"] } unicode-width = "0.1.8" number_prefix = "0.4" term_grid = "0.1.5" diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 962ce164b..a30cda01d 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -12,7 +12,7 @@ extern crate uucore; use clap::{ builder::{NonEmptyStringValueParser, ValueParser}, - crate_version, Arg, Command, + crate_version, Arg, ArgAction, Command, }; use glob::{MatchOptions, Pattern}; use lscolors::LsColors; @@ -268,7 +268,7 @@ impl Display for LsError { } } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub enum Format { Columns, Long, @@ -328,7 +328,7 @@ fn parse_time_style(options: &clap::ArgMatches) -> Result { if let Some(field) = options.get_one::(options::TIME_STYLE) { //If both FULL_TIME and TIME_STYLE are present //The one added last is dominant - if options.contains_id(options::FULL_TIME) + if options.get_flag(options::FULL_TIME) && options.indices_of(options::FULL_TIME).unwrap().last() > options.indices_of(options::TIME_STYLE).unwrap().last() { @@ -348,7 +348,7 @@ fn parse_time_style(options: &clap::ArgMatches) -> Result { }, } } - } else if options.contains_id(options::FULL_TIME) { + } else if options.get_flag(options::FULL_TIME) { Ok(TimeStyle::FullIso) } else { Ok(TimeStyle::Locale) @@ -425,7 +425,7 @@ struct PaddingCollection { impl Config { #[allow(clippy::cognitive_complexity)] pub fn from(options: &clap::ArgMatches) -> UResult { - let context = options.contains_id(options::CONTEXT); + let context = options.get_flag(options::CONTEXT); let (mut format, opt) = if let Some(format_) = options.get_one::(options::FORMAT) { ( match format_.as_str() { @@ -439,13 +439,13 @@ impl Config { }, Some(options::FORMAT), ) - } else if options.contains_id(options::format::LONG) { + } else if options.get_flag(options::format::LONG) { (Format::Long, Some(options::format::LONG)) - } else if options.contains_id(options::format::ACROSS) { + } else if options.get_flag(options::format::ACROSS) { (Format::Across, Some(options::format::ACROSS)) - } else if options.contains_id(options::format::COMMAS) { + } else if options.get_flag(options::format::COMMAS) { (Format::Commas, Some(options::format::COMMAS)) - } else if options.contains_id(options::format::COLUMNS) { + } else if options.get_flag(options::format::COLUMNS) { (Format::Columns, Some(options::format::COLUMNS)) } else if atty::is(atty::Stream::Stdout) { (Format::Columns, None) @@ -479,21 +479,30 @@ impl Config { options::FULL_TIME, ] .iter() - .flat_map(|opt| options.indices_of(opt)) + .flat_map(|opt| { + if options.value_source(opt) == Some(clap::parser::ValueSource::CommandLine) { + options.indices_of(opt) + } else { + None + } + }) .flatten() .any(|i| i >= idx) { format = Format::Long; } else if let Some(mut indices) = options.indices_of(options::format::ONE_LINE) { - if indices.any(|i| i > idx) { + if options.value_source(options::format::ONE_LINE) + == Some(clap::parser::ValueSource::CommandLine) + && indices.any(|i| i > idx) + { format = Format::OneLine; } } } - let files = if options.contains_id(options::files::ALL) { + let files = if options.get_flag(options::files::ALL) { Files::All - } else if options.contains_id(options::files::ALMOST_ALL) { + } else if options.get_flag(options::files::ALMOST_ALL) { Files::AlmostAll } else { Files::Normal @@ -510,15 +519,15 @@ impl Config { // below should never happen as clap already restricts the values. _ => unreachable!("Invalid field for --sort"), } - } else if options.contains_id(options::sort::TIME) { + } else if options.get_flag(options::sort::TIME) { Sort::Time - } else if options.contains_id(options::sort::SIZE) { + } else if options.get_flag(options::sort::SIZE) { Sort::Size - } else if options.contains_id(options::sort::NONE) { + } else if options.get_flag(options::sort::NONE) { Sort::None - } else if options.contains_id(options::sort::VERSION) { + } else if options.get_flag(options::sort::VERSION) { Sort::Version - } else if options.contains_id(options::sort::EXTENSION) { + } else if options.get_flag(options::sort::EXTENSION) { Sort::Extension } else { Sort::Name @@ -532,9 +541,9 @@ impl Config { // below should never happen as clap already restricts the values. _ => unreachable!("Invalid field for --time"), } - } else if options.contains_id(options::time::ACCESS) { + } else if options.get_flag(options::time::ACCESS) { Time::Access - } else if options.contains_id(options::time::CHANGE) { + } else if options.get_flag(options::time::CHANGE) { Time::Change } else { Time::Modification @@ -555,14 +564,14 @@ impl Config { .get_one::(options::size::BLOCK_SIZE) .unwrap() .eq("si") - || options.contains_id(options::size::SI); + || options.get_flag(options::size::SI); let opt_hr = (cmd_line_bs.is_some() && options .get_one::(options::size::BLOCK_SIZE) .unwrap() .eq("human-readable")) - || options.contains_id(options::size::HUMAN_READABLE); - let opt_kb = options.contains_id(options::size::KIBIBYTES); + || options.get_flag(options::size::HUMAN_READABLE); + let opt_kb = options.get_flag(options::size::KIBIBYTES); let bs_env_var = std::env::var_os("BLOCK_SIZE"); let ls_bs_env_var = std::env::var_os("LS_BLOCK_SIZE"); @@ -611,12 +620,12 @@ impl Config { }; let long = { - let author = options.contains_id(options::AUTHOR); - let group = !options.contains_id(options::NO_GROUP) - && !options.contains_id(options::format::LONG_NO_GROUP); - let owner = !options.contains_id(options::format::LONG_NO_OWNER); + let author = options.get_flag(options::AUTHOR); + let group = !options.get_flag(options::NO_GROUP) + && !options.get_flag(options::format::LONG_NO_GROUP); + let owner = !options.get_flag(options::format::LONG_NO_OWNER); #[cfg(unix)] - let numeric_uid_gid = options.contains_id(options::format::LONG_NUMERIC_UID_GID); + let numeric_uid_gid = options.get_flag(options::format::LONG_NUMERIC_UID_GID); LongFormat { author, group, @@ -660,9 +669,9 @@ impl Config { }; #[allow(clippy::needless_bool)] - let mut show_control = if options.contains_id(options::HIDE_CONTROL_CHARS) { + let mut show_control = if options.get_flag(options::HIDE_CONTROL_CHARS) { false - } else if options.contains_id(options::SHOW_CONTROL_CHARS) { + } else if options.get_flag(options::SHOW_CONTROL_CHARS) { true } else { !atty::is(atty::Stream::Stdout) @@ -703,13 +712,13 @@ impl Config { }, _ => unreachable!("Should have been caught by Clap"), } - } else if options.contains_id(options::quoting::LITERAL) { + } else if options.get_flag(options::quoting::LITERAL) { QuotingStyle::Literal { show_control } - } else if options.contains_id(options::quoting::ESCAPE) { + } else if options.get_flag(options::quoting::ESCAPE) { QuotingStyle::C { quotes: quoting_style::Quotes::None, } - } else if options.contains_id(options::quoting::C) { + } else if options.get_flag(options::quoting::C) { QuotingStyle::C { quotes: quoting_style::Quotes::Double, } @@ -745,9 +754,9 @@ impl Config { } &_ => IndicatorStyle::None, } - } else if options.contains_id(options::indicator_style::SLASH) { + } else if options.get_flag(options::indicator_style::SLASH) { IndicatorStyle::Slash - } else if options.contains_id(options::indicator_style::FILE_TYPE) { + } else if options.get_flag(options::indicator_style::FILE_TYPE) { IndicatorStyle::FileType } else { IndicatorStyle::None @@ -756,7 +765,7 @@ impl Config { let mut ignore_patterns: Vec = Vec::new(); - if options.contains_id(options::IGNORE_BACKUPS) { + if options.get_flag(options::IGNORE_BACKUPS) { ignore_patterns.push(Pattern::new("*~").unwrap()); ignore_patterns.push(Pattern::new(".*~").unwrap()); } @@ -815,7 +824,13 @@ impl Config { options::quoting::ESCAPE, options::quoting::LITERAL, ]; - let get_last = |flag: &str| -> usize { options.index_of(flag).unwrap_or(0) }; + let get_last = |flag: &str| -> usize { + if options.value_source(flag) == Some(clap::parser::ValueSource::CommandLine) { + options.index_of(flag).unwrap_or(0) + } else { + 0 + } + }; if get_last(options::ZERO) > zero_formats_opts .into_iter() @@ -863,13 +878,13 @@ impl Config { None }; - let dereference = if options.contains_id(options::dereference::ALL) { + let dereference = if options.get_flag(options::dereference::ALL) { Dereference::All - } else if options.contains_id(options::dereference::ARGS) { + } else if options.get_flag(options::dereference::ARGS) { Dereference::Args - } else if options.contains_id(options::dereference::DIR_ARGS) { + } else if options.get_flag(options::dereference::DIR_ARGS) { Dereference::DirArgs - } else if options.contains_id(options::DIRECTORY) + } else if options.get_flag(options::DIRECTORY) || indicator_style == IndicatorStyle::Classify || format == Format::Long { @@ -882,18 +897,18 @@ impl Config { format, files, sort, - recursive: options.contains_id(options::RECURSIVE), - reverse: options.contains_id(options::REVERSE), + recursive: options.get_flag(options::RECURSIVE), + reverse: options.get_flag(options::REVERSE), dereference, ignore_patterns, size_format, - directory: options.contains_id(options::DIRECTORY), + directory: options.get_flag(options::DIRECTORY), time, color, #[cfg(unix)] - inode: options.contains_id(options::INODE), + inode: options.get_flag(options::INODE), long, - alloc_size: options.contains_id(options::size::ALLOCATION_SIZE), + alloc_size: options.get_flag(options::size::ALLOCATION_SIZE), block_size, width, quoting_style, @@ -910,8 +925,8 @@ impl Config { false } }, - group_directories_first: options.contains_id(options::GROUP_DIRECTORIES_FIRST), - eol: if options.contains_id(options::ZERO) { + group_directories_first: options.get_flag(options::GROUP_DIRECTORIES_FIRST), + eol: if options.get_flag(options::ZERO) { '\0' } else { '\n' @@ -936,23 +951,24 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { list(locs, &config) } -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)) .about(ABOUT) .infer_long_args(true) + .disable_help_flag(true) .arg( Arg::new(options::HELP) .long(options::HELP) - .help("Print help information."), + .help("Print help information.") + .action(ArgAction::Help), ) // Format arguments .arg( Arg::new(options::FORMAT) .long(options::FORMAT) .help("Set the display format.") - .takes_value(true) .value_parser([ "long", "verbose", @@ -983,7 +999,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::format::LONG, options::format::ACROSS, options::format::COLUMNS, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::format::LONG) @@ -996,7 +1013,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::format::LONG, options::format::ACROSS, options::format::COLUMNS, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::format::ACROSS) @@ -1008,7 +1026,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::format::LONG, options::format::ACROSS, options::format::COLUMNS, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( // silently ignored (see #3624) @@ -1016,7 +1035,6 @@ pub fn uu_app<'a>() -> Command<'a> { .short('T') .long(options::format::TAB_SIZE) .env("TABSIZE") - .takes_value(true) .value_name("COLS") .help("Assume tab stops at each COLS instead of 8 (unimplemented)"), ) @@ -1030,20 +1048,23 @@ pub fn uu_app<'a>() -> Command<'a> { options::format::LONG, options::format::ACROSS, options::format::COLUMNS, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::ZERO) .long(options::ZERO) .conflicts_with(options::DIRED) .overrides_with(options::ZERO) - .help("List entries separated by ASCII NUL characters."), + .help("List entries separated by ASCII NUL characters.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DIRED) .long(options::DIRED) .short('D') - .hide(true), + .hide(true) + .action(ArgAction::SetTrue), ) // The next four arguments do not override with the other format // options, see the comment in Config::from for the reason. @@ -1055,7 +1076,7 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::format::ONE_LINE) .short('1') .help("List one file per line.") - .multiple_occurrences(true), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::format::LONG_NO_GROUP) @@ -1064,26 +1085,25 @@ pub fn uu_app<'a>() -> Command<'a> { "Long format without group information. \ Identical to --format=long with --no-group.", ) - .multiple_occurrences(true), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::format::LONG_NO_OWNER) .short('g') .help("Long format without owner information.") - .multiple_occurrences(true), + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::format::LONG_NUMERIC_UID_GID) .short('n') .long(options::format::LONG_NUMERIC_UID_GID) .help("-l with numeric UIDs and GIDs.") - .multiple_occurrences(true), + .action(ArgAction::SetTrue), ) // Quoting style .arg( Arg::new(options::QUOTING_STYLE) .long(options::QUOTING_STYLE) - .takes_value(true) .help("Set quoting style.") .value_parser([ "literal", @@ -1111,7 +1131,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::quoting::LITERAL, options::quoting::ESCAPE, options::quoting::C, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::quoting::ESCAPE) @@ -1123,7 +1144,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::quoting::LITERAL, options::quoting::ESCAPE, options::quoting::C, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::quoting::C) @@ -1135,7 +1157,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::quoting::LITERAL, options::quoting::ESCAPE, options::quoting::C, - ]), + ]) + .action(ArgAction::SetTrue), ) // Control characters .arg( @@ -1143,13 +1166,15 @@ pub fn uu_app<'a>() -> Command<'a> { .short('q') .long(options::HIDE_CONTROL_CHARS) .help("Replace control characters with '?' if they are not escaped.") - .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), + .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SHOW_CONTROL_CHARS) .long(options::SHOW_CONTROL_CHARS) .help("Show control characters 'as is' if they are not escaped.") - .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), + .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]) + .action(ArgAction::SetTrue), ) // Time arguments .arg( @@ -1162,7 +1187,6 @@ pub fn uu_app<'a>() -> Command<'a> { \tbirth time: birth, creation;", ) .value_name("field") - .takes_value(true) .value_parser([ "atime", "access", "use", "ctime", "status", "birth", "creation", ]) @@ -1179,7 +1203,8 @@ pub fn uu_app<'a>() -> Command<'a> { time. When explicitly sorting by time (--sort=time or -t) or when not \ using a long listing format, sort according to the status change time.", ) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::time::ACCESS) @@ -1190,14 +1215,14 @@ pub fn uu_app<'a>() -> Command<'a> { sorting by time (--sort=time or -t) or when not using a long listing \ format, sort according to the access time.", ) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]) + .action(ArgAction::SetTrue), ) // Hide and ignore .arg( Arg::new(options::HIDE) .long(options::HIDE) - .takes_value(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_name("PATTERN") .help( "do not list implied entries matching shell PATTERN (overridden by -a or -A)", @@ -1207,8 +1232,7 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::IGNORE) .short('I') .long(options::IGNORE) - .takes_value(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_name("PATTERN") .help("do not list implied entries matching shell PATTERN"), ) @@ -1216,7 +1240,8 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::IGNORE_BACKUPS) .short('B') .long(options::IGNORE_BACKUPS) - .help("Ignore entries which end with ~."), + .help("Ignore entries which end with ~.") + .action(ArgAction::SetTrue), ) // Sort arguments .arg( @@ -1224,7 +1249,6 @@ pub fn uu_app<'a>() -> Command<'a> { .long(options::SORT) .help("Sort by : name, none (-U), time (-t), size (-S) or extension (-X)") .value_name("field") - .takes_value(true) .value_parser(["name", "none", "time", "size", "version", "extension"]) .require_equals(true) .overrides_with_all(&[ @@ -1247,7 +1271,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::sort::TIME) @@ -1260,7 +1285,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::sort::VERSION) @@ -1273,7 +1299,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::sort::EXTENSION) @@ -1286,7 +1313,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::sort::NONE) @@ -1303,7 +1331,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]), + ]) + .action(ArgAction::SetTrue), ) // Dereferencing .arg( @@ -1318,7 +1347,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::dereference::DIR_ARGS) @@ -1331,7 +1361,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::dereference::ARGS) @@ -1342,40 +1373,42 @@ pub fn uu_app<'a>() -> Command<'a> { options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, - ]), + ]) + .action(ArgAction::SetTrue), ) // Long format options .arg( Arg::new(options::NO_GROUP) .long(options::NO_GROUP) .short('G') - .help("Do not show group in long format."), + .help("Do not show group in long format.") + .action(ArgAction::SetTrue), ) .arg(Arg::new(options::AUTHOR).long(options::AUTHOR).help( - "Show author in long format. \ - On the supported platforms, the author always matches the file owner.", - )) + "Show author in long format. On the supported platforms, \ + the author always matches the file owner.", + ).action(ArgAction::SetTrue)) // Other Flags .arg( Arg::new(options::files::ALL) .short('a') .long(options::files::ALL) // Overrides -A (as the order matters) - .overrides_with(options::files::ALMOST_ALL) - .multiple_occurrences(true) - .help("Do not ignore hidden files (files with names that start with '.')."), + .overrides_with_all([options::files::ALL, options::files::ALMOST_ALL]) + .help("Do not ignore hidden files (files with names that start with '.').") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::files::ALMOST_ALL) .short('A') .long(options::files::ALMOST_ALL) // Overrides -a (as the order matters) - .overrides_with(options::files::ALL) - .multiple_occurrences(true) + .overrides_with_all([options::files::ALL, options::files::ALMOST_ALL]) .help( "In a directory, do not ignore all file names that start with '.', \ only ignore '.' and '..'.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DIRECTORY) @@ -1386,14 +1419,16 @@ pub fn uu_app<'a>() -> Command<'a> { This will not follow symbolic links unless one of `--dereference-command-line \ (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \ specified.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::size::HUMAN_READABLE) .short('h') .long(options::size::HUMAN_READABLE) .help("Print human readable file sizes (e.g. 1K 234M 56G).") - .overrides_with(options::size::SI), + .overrides_with(options::size::SI) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::size::KIBIBYTES) @@ -1402,17 +1437,18 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "default to 1024-byte blocks for file system usage; used only with -s and per \ directory totals", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::size::SI) .long(options::size::SI) - .help("Print human readable file sizes using powers of 1000 instead of 1024."), + .help("Print human readable file sizes using powers of 1000 instead of 1024.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::size::BLOCK_SIZE) .long(options::size::BLOCK_SIZE) - .takes_value(true) .require_equals(true) .value_name("BLOCK_SIZE") .help("scale sizes by BLOCK_SIZE when printing them"), @@ -1421,7 +1457,8 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::INODE) .short('i') .long(options::INODE) - .help("print the index number of each file"), + .help("print the index number of each file") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::REVERSE) @@ -1430,38 +1467,39 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "Reverse whatever the sorting method is e.g., list files in reverse \ alphabetical order, youngest first, smallest first, or whatever.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::RECURSIVE) .short('R') .long(options::RECURSIVE) - .help("List the contents of all directories recursively."), + .help("List the contents of all directories recursively.") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::WIDTH) .long(options::WIDTH) .short('w') .help("Assume that the terminal is COLS columns wide.") - .value_name("COLS") - .takes_value(true), + .value_name("COLS"), ) .arg( Arg::new(options::size::ALLOCATION_SIZE) .short('s') .long(options::size::ALLOCATION_SIZE) - .help("print the allocated size of each file, in blocks"), + .help("print the allocated size of each file, in blocks") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::COLOR) .long(options::COLOR) .help("Color output based on file type.") - .takes_value(true) .value_parser([ "always", "yes", "force", "auto", "tty", "if-tty", "never", "no", "none", ]) .require_equals(true) - .min_values(0), + .num_args(0..=1), ) .arg( Arg::new(options::INDICATOR_STYLE) @@ -1470,7 +1508,6 @@ pub fn uu_app<'a>() -> Command<'a> { "Append indicator with style WORD to entry names: \ none (default), slash (-p), file-type (--file-type), classify (-F)", ) - .takes_value(true) .value_parser(["none", "slash", "file-type", "classify"]) .overrides_with_all(&[ options::indicator_style::FILE_TYPE, @@ -1501,14 +1538,13 @@ pub fn uu_app<'a>() -> Command<'a> { --dereference-command-line (-H), --dereference (-L), or \ --dereference-command-line-symlink-to-dir options are specified.", ) - .takes_value(true) .value_name("when") .value_parser([ "always", "yes", "force", "auto", "tty", "if-tty", "never", "no", "none", ]) .default_missing_value("always") .require_equals(true) - .min_values(0) + .num_args(0..=1) .overrides_with_all(&[ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, @@ -1525,7 +1561,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::indicator_style::SLASH, options::indicator_style::CLASSIFY, options::INDICATOR_STYLE, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::indicator_style::SLASH) @@ -1536,7 +1573,8 @@ pub fn uu_app<'a>() -> Command<'a> { options::indicator_style::SLASH, options::indicator_style::CLASSIFY, options::INDICATOR_STYLE, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( //This still needs support for posix-* @@ -1552,13 +1590,15 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::FULL_TIME) .long(options::FULL_TIME) .overrides_with(options::FULL_TIME) - .help("like -l --time-style=full-iso"), + .help("like -l --time-style=full-iso") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::CONTEXT) .short('Z') .long(options::CONTEXT) - .help(CONTEXT_HELP_TEXT), + .help(CONTEXT_HELP_TEXT) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::GROUP_DIRECTORIES_FIRST) @@ -1566,13 +1606,13 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "group directories before files; can be augmented with \ a --sort option, but any use of --sort=none (-U) disables grouping", - ), + ) + .action(ArgAction::SetTrue), ) // Positional arguments .arg( Arg::new(options::PATHS) - .multiple_occurrences(true) - .takes_value(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath) .value_parser(ValueParser::os_string()), ) diff --git a/src/uu/mkdir/Cargo.toml b/src/uu/mkdir/Cargo.toml index d855cd3f0..54a644ca2 100644 --- a/src/uu/mkdir/Cargo.toml +++ b/src/uu/mkdir/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/mkdir.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "mode"] } [[bin]] diff --git a/src/uu/mkdir/src/mkdir.rs b/src/uu/mkdir/src/mkdir.rs index 02e357dc3..e922ec1d1 100644 --- a/src/uu/mkdir/src/mkdir.rs +++ b/src/uu/mkdir/src/mkdir.rs @@ -12,7 +12,7 @@ extern crate uucore; use clap::builder::ValueParser; use clap::parser::ValuesRef; -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use std::ffi::OsString; use std::path::{Path, PathBuf}; #[cfg(not(windows))] @@ -35,8 +35,8 @@ mod options { pub const DIRS: &str = "dirs"; } -fn get_long_usage() -> String { - String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.") +fn get_long_usage() -> &'static str { + "Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'." } #[cfg(windows)] @@ -91,20 +91,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // Before we can parse 'args' with clap (and previously getopts), // a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE"). let mode_had_minus_prefix = strip_minus_from_mode(&mut args); - let after_help = get_long_usage(); // Linux-specific options, not implemented // opts.optflag("Z", "context", "set SELinux security context" + // " of each created directory to CTX"), let matches = uu_app() - .after_help(&after_help[..]) + .after_help(get_long_usage()) .try_get_matches_from(args)?; let dirs = matches .get_many::(options::DIRS) .unwrap_or_default(); - let verbose = matches.contains_id(options::VERBOSE); - let recursive = matches.contains_id(options::PARENTS); + let verbose = matches.get_flag(options::VERBOSE); + let recursive = matches.get_flag(options::PARENTS); match get_mode(&matches, mode_had_minus_prefix) { Ok(mode) => exec(dirs, recursive, mode, verbose), @@ -112,7 +111,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!()) .about(ABOUT) @@ -122,26 +121,26 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::MODE) .short('m') .long(options::MODE) - .help("set file mode (not implemented on windows)") - .takes_value(true), + .help("set file mode (not implemented on windows)"), ) .arg( Arg::new(options::PARENTS) .short('p') .long(options::PARENTS) - .help("make parent directories as needed"), + .help("make parent directories as needed") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::VERBOSE) .short('v') .long(options::VERBOSE) - .help("print a message for each printed directory"), + .help("print a message for each printed directory") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::DIRS) - .multiple_occurrences(true) - .takes_value(true) - .min_values(1) + .action(ArgAction::Append) + .num_args(1..) .value_parser(ValueParser::os_string()) .value_hint(clap::ValueHint::DirPath), ) diff --git a/src/uu/mkfifo/Cargo.toml b/src/uu/mkfifo/Cargo.toml index 25912ccbc..f932697ff 100644 --- a/src/uu/mkfifo/Cargo.toml +++ b/src/uu/mkfifo/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/mkfifo.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" } diff --git a/src/uu/mkfifo/src/mkfifo.rs b/src/uu/mkfifo/src/mkfifo.rs index 4e82d95ab..33344a6f2 100644 --- a/src/uu/mkfifo/src/mkfifo.rs +++ b/src/uu/mkfifo/src/mkfifo.rs @@ -8,7 +8,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use libc::mkfifo; use std::ffi::CString; use uucore::display::Quotable; @@ -35,7 +35,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if matches.contains_id(options::CONTEXT) { return Err(USimpleError::new(1, "--context is not implemented")); } - if matches.contains_id(options::SE_LINUX_SECURITY_CONTEXT) { + if matches.get_flag(options::SE_LINUX_SECURITY_CONTEXT) { return Err(USimpleError::new(1, "-Z is not implemented")); } @@ -68,7 +68,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .name(NAME) .version(crate_version!()) @@ -81,12 +81,13 @@ pub fn uu_app<'a>() -> Command<'a> { .long(options::MODE) .help("file permissions for the fifo") .default_value("0666") - .value_name("0666"), + .value_name("MODE"), ) .arg( Arg::new(options::SE_LINUX_SECURITY_CONTEXT) .short('Z') - .help("set the SELinux security context to default type"), + .help("set the SELinux security context to default type") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::CONTEXT) @@ -100,7 +101,7 @@ pub fn uu_app<'a>() -> Command<'a> { .arg( Arg::new(options::FIFO) .hide(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath), ) } 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/src/uu/mktemp/Cargo.toml b/src/uu/mktemp/Cargo.toml index 5f0d0b1e8..ddabaabcd 100644 --- a/src/uu/mktemp/Cargo.toml +++ b/src/uu/mktemp/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/mktemp.rs" [dependencies] -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } rand = "0.8" tempfile = "3" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 54e03ebc1..5e7234b76 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -8,7 +8,7 @@ // spell-checker:ignore (paths) GPGHome findxs -use clap::{crate_version, Arg, ArgMatches, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use uucore::display::{println_verbatim, Quotable}; use uucore::error::{FromIo, UError, UResult, UUsageError}; use uucore::format_usage; @@ -197,12 +197,12 @@ impl Options { } }; Self { - directory: matches.contains_id(OPT_DIRECTORY), - dry_run: matches.contains_id(OPT_DRY_RUN), - quiet: matches.contains_id(OPT_QUIET), + directory: matches.get_flag(OPT_DIRECTORY), + dry_run: matches.get_flag(OPT_DRY_RUN), + quiet: matches.get_flag(OPT_QUIET), tmpdir, suffix: matches.get_one::(OPT_SUFFIX).map(String::from), - treat_as_template: matches.contains_id(OPT_T), + treat_as_template: matches.get_flag(OPT_T), template, } } @@ -340,7 +340,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = match uu_app().try_get_matches_from(&args) { Ok(m) => m, Err(e) => { - if e.kind == clap::error::ErrorKind::TooManyValues && e.info[0] == "