diff --git a/Cargo.lock b/Cargo.lock index 7fbb8b89e..ce1f7a800 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "coreutils" -version = "0.0.7" +version = "0.0.8" dependencies = [ "atty", "chrono", @@ -1113,6 +1113,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +[[package]] +name = "memmap2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.4" @@ -2205,7 +2214,7 @@ checksum = "7cf7d77f457ef8dfa11e4cd5933c5ddb5dc52a94664071951219a97710f0a32b" [[package]] name = "uu_arch" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "platform-info", @@ -2215,7 +2224,7 @@ dependencies = [ [[package]] name = "uu_base32" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2224,7 +2233,7 @@ dependencies = [ [[package]] name = "uu_base64" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uu_base32", @@ -2234,7 +2243,7 @@ dependencies = [ [[package]] name = "uu_basename" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2243,7 +2252,7 @@ dependencies = [ [[package]] name = "uu_basenc" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uu_base32", @@ -2253,7 +2262,7 @@ dependencies = [ [[package]] name = "uu_cat" -version = "0.0.7" +version = "0.0.8" dependencies = [ "atty", "clap", @@ -2267,7 +2276,7 @@ dependencies = [ [[package]] name = "uu_chcon" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "fts-sys", @@ -2280,7 +2289,7 @@ dependencies = [ [[package]] name = "uu_chgrp" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2289,7 +2298,7 @@ dependencies = [ [[package]] name = "uu_chmod" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2300,7 +2309,7 @@ dependencies = [ [[package]] name = "uu_chown" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2309,7 +2318,7 @@ dependencies = [ [[package]] name = "uu_chroot" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2318,7 +2327,7 @@ dependencies = [ [[package]] name = "uu_cksum" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2328,7 +2337,7 @@ dependencies = [ [[package]] name = "uu_comm" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2338,7 +2347,7 @@ dependencies = [ [[package]] name = "uu_cp" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "exacl", @@ -2356,7 +2365,7 @@ dependencies = [ [[package]] name = "uu_csplit" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "regex", @@ -2367,7 +2376,7 @@ dependencies = [ [[package]] name = "uu_cut" -version = "0.0.7" +version = "0.0.8" dependencies = [ "atty", "bstr", @@ -2379,7 +2388,7 @@ dependencies = [ [[package]] name = "uu_date" -version = "0.0.7" +version = "0.0.8" dependencies = [ "chrono", "clap", @@ -2391,7 +2400,7 @@ dependencies = [ [[package]] name = "uu_dd" -version = "0.0.7" +version = "0.0.8" dependencies = [ "byte-unit", "clap", @@ -2405,7 +2414,7 @@ dependencies = [ [[package]] name = "uu_df" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "number_prefix", @@ -2415,7 +2424,7 @@ dependencies = [ [[package]] name = "uu_dircolors" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "glob", @@ -2425,7 +2434,7 @@ dependencies = [ [[package]] name = "uu_dirname" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2435,7 +2444,7 @@ dependencies = [ [[package]] name = "uu_du" -version = "0.0.7" +version = "0.0.8" dependencies = [ "chrono", "clap", @@ -2446,7 +2455,7 @@ dependencies = [ [[package]] name = "uu_echo" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2455,7 +2464,7 @@ dependencies = [ [[package]] name = "uu_env" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2466,7 +2475,7 @@ dependencies = [ [[package]] name = "uu_expand" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "unicode-width", @@ -2476,7 +2485,7 @@ dependencies = [ [[package]] name = "uu_expr" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2489,7 +2498,7 @@ dependencies = [ [[package]] name = "uu_factor" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "coz", @@ -2504,7 +2513,7 @@ dependencies = [ [[package]] name = "uu_false" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2513,7 +2522,7 @@ dependencies = [ [[package]] name = "uu_fmt" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2524,7 +2533,7 @@ dependencies = [ [[package]] name = "uu_fold" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2533,7 +2542,7 @@ dependencies = [ [[package]] name = "uu_groups" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2542,7 +2551,7 @@ dependencies = [ [[package]] name = "uu_hashsum" -version = "0.0.7" +version = "0.0.8" dependencies = [ "blake2b_simd", "clap", @@ -2562,16 +2571,17 @@ dependencies = [ [[package]] name = "uu_head" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", + "memchr 2.4.0", "uucore", "uucore_procs", ] [[package]] name = "uu_hostid" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2581,7 +2591,7 @@ dependencies = [ [[package]] name = "uu_hostname" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "hostname", @@ -2593,7 +2603,7 @@ dependencies = [ [[package]] name = "uu_id" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "selinux", @@ -2603,7 +2613,7 @@ dependencies = [ [[package]] name = "uu_install" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "file_diff", @@ -2616,7 +2626,7 @@ dependencies = [ [[package]] name = "uu_join" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2625,7 +2635,7 @@ dependencies = [ [[package]] name = "uu_kill" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2635,7 +2645,7 @@ dependencies = [ [[package]] name = "uu_link" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2645,7 +2655,7 @@ dependencies = [ [[package]] name = "uu_ln" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2655,7 +2665,7 @@ dependencies = [ [[package]] name = "uu_logname" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2665,7 +2675,7 @@ dependencies = [ [[package]] name = "uu_ls" -version = "0.0.7" +version = "0.0.8" dependencies = [ "atty", "chrono", @@ -2675,6 +2685,7 @@ dependencies = [ "lscolors", "number_prefix", "once_cell", + "selinux", "term_grid", "termsize", "unicode-width", @@ -2684,7 +2695,7 @@ dependencies = [ [[package]] name = "uu_mkdir" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2694,7 +2705,7 @@ dependencies = [ [[package]] name = "uu_mkfifo" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2704,7 +2715,7 @@ dependencies = [ [[package]] name = "uu_mknod" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2714,7 +2725,7 @@ dependencies = [ [[package]] name = "uu_mktemp" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "rand 0.5.6", @@ -2725,7 +2736,7 @@ dependencies = [ [[package]] name = "uu_more" -version = "0.0.7" +version = "0.0.8" dependencies = [ "atty", "clap", @@ -2741,7 +2752,7 @@ dependencies = [ [[package]] name = "uu_mv" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "fs_extra", @@ -2751,7 +2762,7 @@ dependencies = [ [[package]] name = "uu_nice" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2762,7 +2773,7 @@ dependencies = [ [[package]] name = "uu_nl" -version = "0.0.7" +version = "0.0.8" dependencies = [ "aho-corasick", "clap", @@ -2776,7 +2787,7 @@ dependencies = [ [[package]] name = "uu_nohup" -version = "0.0.7" +version = "0.0.8" dependencies = [ "atty", "clap", @@ -2787,7 +2798,7 @@ dependencies = [ [[package]] name = "uu_nproc" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2798,7 +2809,7 @@ dependencies = [ [[package]] name = "uu_numfmt" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2807,7 +2818,7 @@ dependencies = [ [[package]] name = "uu_od" -version = "0.0.7" +version = "0.0.8" dependencies = [ "byteorder", "clap", @@ -2819,7 +2830,7 @@ dependencies = [ [[package]] name = "uu_paste" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2828,7 +2839,7 @@ dependencies = [ [[package]] name = "uu_pathchk" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2838,7 +2849,7 @@ dependencies = [ [[package]] name = "uu_pinky" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2847,7 +2858,7 @@ dependencies = [ [[package]] name = "uu_pr" -version = "0.0.7" +version = "0.0.8" dependencies = [ "chrono", "clap", @@ -2861,7 +2872,7 @@ dependencies = [ [[package]] name = "uu_printenv" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2870,7 +2881,7 @@ dependencies = [ [[package]] name = "uu_printf" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "itertools 0.8.2", @@ -2880,7 +2891,7 @@ dependencies = [ [[package]] name = "uu_ptx" -version = "0.0.7" +version = "0.0.8" dependencies = [ "aho-corasick", "clap", @@ -2894,7 +2905,7 @@ dependencies = [ [[package]] name = "uu_pwd" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2903,7 +2914,7 @@ dependencies = [ [[package]] name = "uu_readlink" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2913,7 +2924,7 @@ dependencies = [ [[package]] name = "uu_realpath" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2922,7 +2933,7 @@ dependencies = [ [[package]] name = "uu_relpath" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -2931,7 +2942,7 @@ dependencies = [ [[package]] name = "uu_rm" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "remove_dir_all", @@ -2943,7 +2954,7 @@ dependencies = [ [[package]] name = "uu_rmdir" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2953,7 +2964,7 @@ dependencies = [ [[package]] name = "uu_runcon" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "fts-sys", @@ -2966,7 +2977,7 @@ dependencies = [ [[package]] name = "uu_seq" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "num-bigint", @@ -2977,7 +2988,7 @@ dependencies = [ [[package]] name = "uu_shred" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -2988,7 +2999,7 @@ dependencies = [ [[package]] name = "uu_shuf" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "rand 0.5.6", @@ -2998,7 +3009,7 @@ dependencies = [ [[package]] name = "uu_sleep" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3007,7 +3018,7 @@ dependencies = [ [[package]] name = "uu_sort" -version = "0.0.7" +version = "0.0.8" dependencies = [ "binary-heap-plus", "clap", @@ -3027,7 +3038,7 @@ dependencies = [ [[package]] name = "uu_split" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3036,7 +3047,7 @@ dependencies = [ [[package]] name = "uu_stat" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3045,7 +3056,7 @@ dependencies = [ [[package]] name = "uu_stdbuf" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "tempfile", @@ -3056,7 +3067,7 @@ dependencies = [ [[package]] name = "uu_stdbuf_libstdbuf" -version = "0.0.7" +version = "0.0.8" dependencies = [ "cpp", "cpp_build", @@ -3067,7 +3078,7 @@ dependencies = [ [[package]] name = "uu_sum" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3076,7 +3087,7 @@ dependencies = [ [[package]] name = "uu_sync" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -3087,10 +3098,11 @@ dependencies = [ [[package]] name = "uu_tac" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "memchr 2.4.0", + "memmap2", "regex", "uucore", "uucore_procs", @@ -3098,7 +3110,7 @@ dependencies = [ [[package]] name = "uu_tail" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -3112,7 +3124,7 @@ dependencies = [ [[package]] name = "uu_tee" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -3123,7 +3135,7 @@ dependencies = [ [[package]] name = "uu_test" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -3134,7 +3146,7 @@ dependencies = [ [[package]] name = "uu_timeout" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -3145,7 +3157,7 @@ dependencies = [ [[package]] name = "uu_touch" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "filetime", @@ -3156,7 +3168,7 @@ dependencies = [ [[package]] name = "uu_tr" -version = "0.0.7" +version = "0.0.8" dependencies = [ "bit-set", "clap", @@ -3167,7 +3179,7 @@ dependencies = [ [[package]] name = "uu_true" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3176,7 +3188,7 @@ dependencies = [ [[package]] name = "uu_truncate" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3185,7 +3197,7 @@ dependencies = [ [[package]] name = "uu_tsort" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3194,7 +3206,7 @@ dependencies = [ [[package]] name = "uu_tty" -version = "0.0.7" +version = "0.0.8" dependencies = [ "atty", "clap", @@ -3205,7 +3217,7 @@ dependencies = [ [[package]] name = "uu_uname" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "platform-info", @@ -3215,7 +3227,7 @@ dependencies = [ [[package]] name = "uu_unexpand" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "unicode-width", @@ -3225,7 +3237,7 @@ dependencies = [ [[package]] name = "uu_uniq" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "strum", @@ -3236,7 +3248,7 @@ dependencies = [ [[package]] name = "uu_unlink" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3245,7 +3257,7 @@ dependencies = [ [[package]] name = "uu_uptime" -version = "0.0.7" +version = "0.0.8" dependencies = [ "chrono", "clap", @@ -3255,7 +3267,7 @@ dependencies = [ [[package]] name = "uu_users" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3264,7 +3276,7 @@ dependencies = [ [[package]] name = "uu_wc" -version = "0.0.7" +version = "0.0.8" dependencies = [ "bytecount", "clap", @@ -3278,7 +3290,7 @@ dependencies = [ [[package]] name = "uu_who" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "uucore", @@ -3287,7 +3299,7 @@ dependencies = [ [[package]] name = "uu_whoami" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "libc", @@ -3298,7 +3310,7 @@ dependencies = [ [[package]] name = "uu_yes" -version = "0.0.7" +version = "0.0.8" dependencies = [ "clap", "nix 0.20.0", @@ -3308,7 +3320,7 @@ dependencies = [ [[package]] name = "uucore" -version = "0.0.9" +version = "0.0.10" dependencies = [ "clap", "data-encoding", @@ -3331,7 +3343,7 @@ dependencies = [ [[package]] name = "uucore_procs" -version = "0.0.6" +version = "0.0.7" dependencies = [ "proc-macro2", "quote 1.0.9", diff --git a/Cargo.toml b/Cargo.toml index 7b1399abf..9ecea79c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ [package] name = "coreutils" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust" @@ -148,7 +148,7 @@ feat_os_unix_musl = [ # NOTE: # The selinux(-sys) crate requires `libselinux` headers and shared library to be accessible in the C toolchain at compile time. # Running a uutils compiled with `feat_selinux` requires an SELinux enabled Kernel at run time. -feat_selinux = ["cp/selinux", "id/selinux", "selinux", "feat_require_selinux"] +feat_selinux = ["cp/selinux", "id/selinux", "ls/selinux", "selinux", "feat_require_selinux"] # "feat_acl" == set of utilities providing support for acl (access control lists) if enabled with `--features feat_acl`. # NOTE: # On linux, the posix-acl/acl-sys crate requires `libacl` headers and shared library to be accessible in the C toolchain at compile time. @@ -247,110 +247,110 @@ test = [ "uu_test" ] clap = { version = "2.33", features = ["wrap_help"] } lazy_static = { version="1.3" } textwrap = { version="0.14", features=["terminal_size"] } -uucore = { version=">=0.0.9", package="uucore", path="src/uucore" } +uucore = { version=">=0.0.10", package="uucore", path="src/uucore" } selinux = { version="0.2.3", optional = true } # * uutils -uu_test = { optional=true, version="0.0.7", package="uu_test", path="src/uu/test" } +uu_test = { optional=true, version="0.0.8", package="uu_test", path="src/uu/test" } # -arch = { optional=true, version="0.0.7", package="uu_arch", path="src/uu/arch" } -base32 = { optional=true, version="0.0.7", package="uu_base32", path="src/uu/base32" } -base64 = { optional=true, version="0.0.7", package="uu_base64", path="src/uu/base64" } -basename = { optional=true, version="0.0.7", package="uu_basename", path="src/uu/basename" } -basenc = { optional=true, version="0.0.7", package="uu_basenc", path="src/uu/basenc" } -cat = { optional=true, version="0.0.7", package="uu_cat", path="src/uu/cat" } -chcon = { optional=true, version="0.0.7", package="uu_chcon", path="src/uu/chcon" } -chgrp = { optional=true, version="0.0.7", package="uu_chgrp", path="src/uu/chgrp" } -chmod = { optional=true, version="0.0.7", package="uu_chmod", path="src/uu/chmod" } -chown = { optional=true, version="0.0.7", package="uu_chown", path="src/uu/chown" } -chroot = { optional=true, version="0.0.7", package="uu_chroot", path="src/uu/chroot" } -cksum = { optional=true, version="0.0.7", package="uu_cksum", path="src/uu/cksum" } -comm = { optional=true, version="0.0.7", package="uu_comm", path="src/uu/comm" } -cp = { optional=true, version="0.0.7", package="uu_cp", path="src/uu/cp" } -csplit = { optional=true, version="0.0.7", package="uu_csplit", path="src/uu/csplit" } -cut = { optional=true, version="0.0.7", package="uu_cut", path="src/uu/cut" } -date = { optional=true, version="0.0.7", package="uu_date", path="src/uu/date" } -dd = { optional=true, version="0.0.7", package="uu_dd", path="src/uu/dd" } -df = { optional=true, version="0.0.7", package="uu_df", path="src/uu/df" } -dircolors= { optional=true, version="0.0.7", package="uu_dircolors", path="src/uu/dircolors" } -dirname = { optional=true, version="0.0.7", package="uu_dirname", path="src/uu/dirname" } -du = { optional=true, version="0.0.7", package="uu_du", path="src/uu/du" } -echo = { optional=true, version="0.0.7", package="uu_echo", path="src/uu/echo" } -env = { optional=true, version="0.0.7", package="uu_env", path="src/uu/env" } -expand = { optional=true, version="0.0.7", package="uu_expand", path="src/uu/expand" } -expr = { optional=true, version="0.0.7", package="uu_expr", path="src/uu/expr" } -factor = { optional=true, version="0.0.7", package="uu_factor", path="src/uu/factor" } -false = { optional=true, version="0.0.7", package="uu_false", path="src/uu/false" } -fmt = { optional=true, version="0.0.7", package="uu_fmt", path="src/uu/fmt" } -fold = { optional=true, version="0.0.7", package="uu_fold", path="src/uu/fold" } -groups = { optional=true, version="0.0.7", package="uu_groups", path="src/uu/groups" } -hashsum = { optional=true, version="0.0.7", package="uu_hashsum", path="src/uu/hashsum" } -head = { optional=true, version="0.0.7", package="uu_head", path="src/uu/head" } -hostid = { optional=true, version="0.0.7", package="uu_hostid", path="src/uu/hostid" } -hostname = { optional=true, version="0.0.7", package="uu_hostname", path="src/uu/hostname" } -id = { optional=true, version="0.0.7", package="uu_id", path="src/uu/id" } -install = { optional=true, version="0.0.7", package="uu_install", path="src/uu/install" } -join = { optional=true, version="0.0.7", package="uu_join", path="src/uu/join" } -kill = { optional=true, version="0.0.7", package="uu_kill", path="src/uu/kill" } -link = { optional=true, version="0.0.7", package="uu_link", path="src/uu/link" } -ln = { optional=true, version="0.0.7", package="uu_ln", path="src/uu/ln" } -ls = { optional=true, version="0.0.7", package="uu_ls", path="src/uu/ls" } -logname = { optional=true, version="0.0.7", package="uu_logname", path="src/uu/logname" } -mkdir = { optional=true, version="0.0.7", package="uu_mkdir", path="src/uu/mkdir" } -mkfifo = { optional=true, version="0.0.7", package="uu_mkfifo", path="src/uu/mkfifo" } -mknod = { optional=true, version="0.0.7", package="uu_mknod", path="src/uu/mknod" } -mktemp = { optional=true, version="0.0.7", package="uu_mktemp", path="src/uu/mktemp" } -more = { optional=true, version="0.0.7", package="uu_more", path="src/uu/more" } -mv = { optional=true, version="0.0.7", package="uu_mv", path="src/uu/mv" } -nice = { optional=true, version="0.0.7", package="uu_nice", path="src/uu/nice" } -nl = { optional=true, version="0.0.7", package="uu_nl", path="src/uu/nl" } -nohup = { optional=true, version="0.0.7", package="uu_nohup", path="src/uu/nohup" } -nproc = { optional=true, version="0.0.7", package="uu_nproc", path="src/uu/nproc" } -numfmt = { optional=true, version="0.0.7", package="uu_numfmt", path="src/uu/numfmt" } -od = { optional=true, version="0.0.7", package="uu_od", path="src/uu/od" } -paste = { optional=true, version="0.0.7", package="uu_paste", path="src/uu/paste" } -pathchk = { optional=true, version="0.0.7", package="uu_pathchk", path="src/uu/pathchk" } -pinky = { optional=true, version="0.0.7", package="uu_pinky", path="src/uu/pinky" } -pr = { optional=true, version="0.0.7", package="uu_pr", path="src/uu/pr" } -printenv = { optional=true, version="0.0.7", package="uu_printenv", path="src/uu/printenv" } -printf = { optional=true, version="0.0.7", package="uu_printf", path="src/uu/printf" } -ptx = { optional=true, version="0.0.7", package="uu_ptx", path="src/uu/ptx" } -pwd = { optional=true, version="0.0.7", package="uu_pwd", path="src/uu/pwd" } -readlink = { optional=true, version="0.0.7", package="uu_readlink", path="src/uu/readlink" } -realpath = { optional=true, version="0.0.7", package="uu_realpath", path="src/uu/realpath" } -relpath = { optional=true, version="0.0.7", package="uu_relpath", path="src/uu/relpath" } -rm = { optional=true, version="0.0.7", package="uu_rm", path="src/uu/rm" } -rmdir = { optional=true, version="0.0.7", package="uu_rmdir", path="src/uu/rmdir" } -runcon = { optional=true, version="0.0.7", package="uu_runcon", path="src/uu/runcon" } -seq = { optional=true, version="0.0.7", package="uu_seq", path="src/uu/seq" } -shred = { optional=true, version="0.0.7", package="uu_shred", path="src/uu/shred" } -shuf = { optional=true, version="0.0.7", package="uu_shuf", path="src/uu/shuf" } -sleep = { optional=true, version="0.0.7", package="uu_sleep", path="src/uu/sleep" } -sort = { optional=true, version="0.0.7", package="uu_sort", path="src/uu/sort" } -split = { optional=true, version="0.0.7", package="uu_split", path="src/uu/split" } -stat = { optional=true, version="0.0.7", package="uu_stat", path="src/uu/stat" } -stdbuf = { optional=true, version="0.0.7", package="uu_stdbuf", path="src/uu/stdbuf" } -sum = { optional=true, version="0.0.7", package="uu_sum", path="src/uu/sum" } -sync = { optional=true, version="0.0.7", package="uu_sync", path="src/uu/sync" } -tac = { optional=true, version="0.0.7", package="uu_tac", path="src/uu/tac" } -tail = { optional=true, version="0.0.7", package="uu_tail", path="src/uu/tail" } -tee = { optional=true, version="0.0.7", package="uu_tee", path="src/uu/tee" } -timeout = { optional=true, version="0.0.7", package="uu_timeout", path="src/uu/timeout" } -touch = { optional=true, version="0.0.7", package="uu_touch", path="src/uu/touch" } -tr = { optional=true, version="0.0.7", package="uu_tr", path="src/uu/tr" } -true = { optional=true, version="0.0.7", package="uu_true", path="src/uu/true" } -truncate = { optional=true, version="0.0.7", package="uu_truncate", path="src/uu/truncate" } -tsort = { optional=true, version="0.0.7", package="uu_tsort", path="src/uu/tsort" } -tty = { optional=true, version="0.0.7", package="uu_tty", path="src/uu/tty" } -uname = { optional=true, version="0.0.7", package="uu_uname", path="src/uu/uname" } -unexpand = { optional=true, version="0.0.7", package="uu_unexpand", path="src/uu/unexpand" } -uniq = { optional=true, version="0.0.7", package="uu_uniq", path="src/uu/uniq" } -unlink = { optional=true, version="0.0.7", package="uu_unlink", path="src/uu/unlink" } -uptime = { optional=true, version="0.0.7", package="uu_uptime", path="src/uu/uptime" } -users = { optional=true, version="0.0.7", package="uu_users", path="src/uu/users" } -wc = { optional=true, version="0.0.7", package="uu_wc", path="src/uu/wc" } -who = { optional=true, version="0.0.7", package="uu_who", path="src/uu/who" } -whoami = { optional=true, version="0.0.7", package="uu_whoami", path="src/uu/whoami" } -yes = { optional=true, version="0.0.7", package="uu_yes", path="src/uu/yes" } +arch = { optional=true, version="0.0.8", package="uu_arch", path="src/uu/arch" } +base32 = { optional=true, version="0.0.8", package="uu_base32", path="src/uu/base32" } +base64 = { optional=true, version="0.0.8", package="uu_base64", path="src/uu/base64" } +basename = { optional=true, version="0.0.8", package="uu_basename", path="src/uu/basename" } +basenc = { optional=true, version="0.0.8", package="uu_basenc", path="src/uu/basenc" } +cat = { optional=true, version="0.0.8", package="uu_cat", path="src/uu/cat" } +chcon = { optional=true, version="0.0.8", package="uu_chcon", path="src/uu/chcon" } +chgrp = { optional=true, version="0.0.8", package="uu_chgrp", path="src/uu/chgrp" } +chmod = { optional=true, version="0.0.8", package="uu_chmod", path="src/uu/chmod" } +chown = { optional=true, version="0.0.8", package="uu_chown", path="src/uu/chown" } +chroot = { optional=true, version="0.0.8", package="uu_chroot", path="src/uu/chroot" } +cksum = { optional=true, version="0.0.8", package="uu_cksum", path="src/uu/cksum" } +comm = { optional=true, version="0.0.8", package="uu_comm", path="src/uu/comm" } +cp = { optional=true, version="0.0.8", package="uu_cp", path="src/uu/cp" } +csplit = { optional=true, version="0.0.8", package="uu_csplit", path="src/uu/csplit" } +cut = { optional=true, version="0.0.8", package="uu_cut", path="src/uu/cut" } +date = { optional=true, version="0.0.8", package="uu_date", path="src/uu/date" } +dd = { optional=true, version="0.0.8", package="uu_dd", path="src/uu/dd" } +df = { optional=true, version="0.0.8", package="uu_df", path="src/uu/df" } +dircolors= { optional=true, version="0.0.8", package="uu_dircolors", path="src/uu/dircolors" } +dirname = { optional=true, version="0.0.8", package="uu_dirname", path="src/uu/dirname" } +du = { optional=true, version="0.0.8", package="uu_du", path="src/uu/du" } +echo = { optional=true, version="0.0.8", package="uu_echo", path="src/uu/echo" } +env = { optional=true, version="0.0.8", package="uu_env", path="src/uu/env" } +expand = { optional=true, version="0.0.8", package="uu_expand", path="src/uu/expand" } +expr = { optional=true, version="0.0.8", package="uu_expr", path="src/uu/expr" } +factor = { optional=true, version="0.0.8", package="uu_factor", path="src/uu/factor" } +false = { optional=true, version="0.0.8", package="uu_false", path="src/uu/false" } +fmt = { optional=true, version="0.0.8", package="uu_fmt", path="src/uu/fmt" } +fold = { optional=true, version="0.0.8", package="uu_fold", path="src/uu/fold" } +groups = { optional=true, version="0.0.8", package="uu_groups", path="src/uu/groups" } +hashsum = { optional=true, version="0.0.8", package="uu_hashsum", path="src/uu/hashsum" } +head = { optional=true, version="0.0.8", package="uu_head", path="src/uu/head" } +hostid = { optional=true, version="0.0.8", package="uu_hostid", path="src/uu/hostid" } +hostname = { optional=true, version="0.0.8", package="uu_hostname", path="src/uu/hostname" } +id = { optional=true, version="0.0.8", package="uu_id", path="src/uu/id" } +install = { optional=true, version="0.0.8", package="uu_install", path="src/uu/install" } +join = { optional=true, version="0.0.8", package="uu_join", path="src/uu/join" } +kill = { optional=true, version="0.0.8", package="uu_kill", path="src/uu/kill" } +link = { optional=true, version="0.0.8", package="uu_link", path="src/uu/link" } +ln = { optional=true, version="0.0.8", package="uu_ln", path="src/uu/ln" } +ls = { optional=true, version="0.0.8", package="uu_ls", path="src/uu/ls" } +logname = { optional=true, version="0.0.8", package="uu_logname", path="src/uu/logname" } +mkdir = { optional=true, version="0.0.8", package="uu_mkdir", path="src/uu/mkdir" } +mkfifo = { optional=true, version="0.0.8", package="uu_mkfifo", path="src/uu/mkfifo" } +mknod = { optional=true, version="0.0.8", package="uu_mknod", path="src/uu/mknod" } +mktemp = { optional=true, version="0.0.8", package="uu_mktemp", path="src/uu/mktemp" } +more = { optional=true, version="0.0.8", package="uu_more", path="src/uu/more" } +mv = { optional=true, version="0.0.8", package="uu_mv", path="src/uu/mv" } +nice = { optional=true, version="0.0.8", package="uu_nice", path="src/uu/nice" } +nl = { optional=true, version="0.0.8", package="uu_nl", path="src/uu/nl" } +nohup = { optional=true, version="0.0.8", package="uu_nohup", path="src/uu/nohup" } +nproc = { optional=true, version="0.0.8", package="uu_nproc", path="src/uu/nproc" } +numfmt = { optional=true, version="0.0.8", package="uu_numfmt", path="src/uu/numfmt" } +od = { optional=true, version="0.0.8", package="uu_od", path="src/uu/od" } +paste = { optional=true, version="0.0.8", package="uu_paste", path="src/uu/paste" } +pathchk = { optional=true, version="0.0.8", package="uu_pathchk", path="src/uu/pathchk" } +pinky = { optional=true, version="0.0.8", package="uu_pinky", path="src/uu/pinky" } +pr = { optional=true, version="0.0.8", package="uu_pr", path="src/uu/pr" } +printenv = { optional=true, version="0.0.8", package="uu_printenv", path="src/uu/printenv" } +printf = { optional=true, version="0.0.8", package="uu_printf", path="src/uu/printf" } +ptx = { optional=true, version="0.0.8", package="uu_ptx", path="src/uu/ptx" } +pwd = { optional=true, version="0.0.8", package="uu_pwd", path="src/uu/pwd" } +readlink = { optional=true, version="0.0.8", package="uu_readlink", path="src/uu/readlink" } +realpath = { optional=true, version="0.0.8", package="uu_realpath", path="src/uu/realpath" } +relpath = { optional=true, version="0.0.8", package="uu_relpath", path="src/uu/relpath" } +rm = { optional=true, version="0.0.8", package="uu_rm", path="src/uu/rm" } +rmdir = { optional=true, version="0.0.8", package="uu_rmdir", path="src/uu/rmdir" } +runcon = { optional=true, version="0.0.8", package="uu_runcon", path="src/uu/runcon" } +seq = { optional=true, version="0.0.8", package="uu_seq", path="src/uu/seq" } +shred = { optional=true, version="0.0.8", package="uu_shred", path="src/uu/shred" } +shuf = { optional=true, version="0.0.8", package="uu_shuf", path="src/uu/shuf" } +sleep = { optional=true, version="0.0.8", package="uu_sleep", path="src/uu/sleep" } +sort = { optional=true, version="0.0.8", package="uu_sort", path="src/uu/sort" } +split = { optional=true, version="0.0.8", package="uu_split", path="src/uu/split" } +stat = { optional=true, version="0.0.8", package="uu_stat", path="src/uu/stat" } +stdbuf = { optional=true, version="0.0.8", package="uu_stdbuf", path="src/uu/stdbuf" } +sum = { optional=true, version="0.0.8", package="uu_sum", path="src/uu/sum" } +sync = { optional=true, version="0.0.8", package="uu_sync", path="src/uu/sync" } +tac = { optional=true, version="0.0.8", package="uu_tac", path="src/uu/tac" } +tail = { optional=true, version="0.0.8", package="uu_tail", path="src/uu/tail" } +tee = { optional=true, version="0.0.8", package="uu_tee", path="src/uu/tee" } +timeout = { optional=true, version="0.0.8", package="uu_timeout", path="src/uu/timeout" } +touch = { optional=true, version="0.0.8", package="uu_touch", path="src/uu/touch" } +tr = { optional=true, version="0.0.8", package="uu_tr", path="src/uu/tr" } +true = { optional=true, version="0.0.8", package="uu_true", path="src/uu/true" } +truncate = { optional=true, version="0.0.8", package="uu_truncate", path="src/uu/truncate" } +tsort = { optional=true, version="0.0.8", package="uu_tsort", path="src/uu/tsort" } +tty = { optional=true, version="0.0.8", package="uu_tty", path="src/uu/tty" } +uname = { optional=true, version="0.0.8", package="uu_uname", path="src/uu/uname" } +unexpand = { optional=true, version="0.0.8", package="uu_unexpand", path="src/uu/unexpand" } +uniq = { optional=true, version="0.0.8", package="uu_uniq", path="src/uu/uniq" } +unlink = { optional=true, version="0.0.8", package="uu_unlink", path="src/uu/unlink" } +uptime = { optional=true, version="0.0.8", package="uu_uptime", path="src/uu/uptime" } +users = { optional=true, version="0.0.8", package="uu_users", path="src/uu/users" } +wc = { optional=true, version="0.0.8", package="uu_wc", path="src/uu/wc" } +who = { optional=true, version="0.0.8", package="uu_who", path="src/uu/who" } +whoami = { optional=true, version="0.0.8", package="uu_whoami", path="src/uu/whoami" } +yes = { optional=true, version="0.0.8", package="uu_yes", path="src/uu/yes" } # this breaks clippy linting with: "tests/by-util/test_factor_benches.rs: No such file or directory (os error 2)" # factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" } @@ -373,7 +373,7 @@ sha1 = { version="0.6", features=["std"] } tempfile = "3.2.0" time = "0.1" unindent = "0.1" -uucore = { version=">=0.0.9", package="uucore", path="src/uucore", features=["entries", "process"] } +uucore = { version=">=0.0.10", package="uucore", path="src/uucore", features=["entries", "process"] } walkdir = "2.2" atty = "0.2" diff --git a/build.rs b/build.rs index 4fbb27cce..261eb5d9a 100644 --- a/build.rs +++ b/build.rs @@ -46,6 +46,8 @@ pub fn main() { "type UtilityMap = HashMap<&'static str, (fn(T) -> i32, fn() -> App<'static, 'static>)>;\n\ \n\ fn util_map() -> UtilityMap {\n\ + \t#[allow(unused_mut)]\n\ + \t#[allow(clippy::let_and_return)]\n\ \tlet mut map = UtilityMap::new();\n\ " .as_bytes(), diff --git a/src/uu/arch/Cargo.toml b/src/uu/arch/Cargo.toml index aa51183d7..c7fc4f9f9 100644 --- a/src/uu/arch/Cargo.toml +++ b/src/uu/arch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_arch" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "arch ~ (uutils) display machine architecture" @@ -17,8 +17,8 @@ path = "src/arch.rs" [dependencies] platform-info = "0.1" clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "arch" diff --git a/src/uu/arch/src/arch.rs b/src/uu/arch/src/arch.rs index 478fef6f1..d23a11cc8 100644 --- a/src/uu/arch/src/arch.rs +++ b/src/uu/arch/src/arch.rs @@ -6,9 +6,6 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use platform_info::*; use clap::{crate_version, App}; diff --git a/src/uu/base32/Cargo.toml b/src/uu/base32/Cargo.toml index bc896bdb2..d5fc40024 100644 --- a/src/uu/base32/Cargo.toml +++ b/src/uu/base32/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_base32" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "base32 ~ (uutils) decode/encode input (base32-encoding)" @@ -16,8 +16,8 @@ path = "src/base32.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features = ["encoding"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features = ["encoding"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "base32" diff --git a/src/uu/base32/src/base32.rs b/src/uu/base32/src/base32.rs index 667fd927e..f4b4b49de 100644 --- a/src/uu/base32/src/base32.rs +++ b/src/uu/base32/src/base32.rs @@ -5,13 +5,10 @@ // For the full copyright and license information, please view the LICENSE file // that was distributed with this source code. -#[macro_use] -extern crate uucore; - use std::io::{stdin, Read}; use clap::App; -use uucore::encoding::Format; +use uucore::{encoding::Format, error::UResult}; pub mod base_common; @@ -24,27 +21,22 @@ static ABOUT: &str = " to attempt to recover from any other non-alphabet bytes in the encoded stream. "; -static VERSION: &str = env!("CARGO_PKG_VERSION"); - -static BASE_CMD_PARSE_ERROR: i32 = 1; fn usage() -> String { format!("{0} [OPTION]... [FILE]", uucore::execution_phrase()) } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let format = Format::Base32; let usage = usage(); - let name = uucore::util_name(); - let config_result: Result = - base_common::parse_base_cmd_args(args, name, VERSION, ABOUT, &usage); - let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s)); + let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?; // Create a reference to stdin so we can return a locked stdin from // parse_base_cmd_args let stdin_raw = stdin(); - let mut input: Box = base_common::get_input(&config, &stdin_raw); + let mut input: Box = base_common::get_input(&config, &stdin_raw)?; base_common::handle_input( &mut input, @@ -52,12 +44,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 { config.wrap_cols, config.ignore_garbage, config.decode, - name, - ); - - 0 + ) } pub fn uu_app() -> App<'static, 'static> { - base_common::base_app(uucore::util_name(), VERSION, ABOUT) + base_common::base_app(ABOUT) } diff --git a/src/uu/base32/src/base_common.rs b/src/uu/base32/src/base_common.rs index 0fd0fa5c4..b07203507 100644 --- a/src/uu/base32/src/base_common.rs +++ b/src/uu/base32/src/base_common.rs @@ -11,13 +11,16 @@ use std::io::{stdout, Read, Write}; use uucore::display::Quotable; use uucore::encoding::{wrap_print, Data, Format}; +use uucore::error::{FromIo, UResult, USimpleError, UUsageError}; use uucore::InvalidEncodingHandling; use std::fs::File; use std::io::{BufReader, Stdin}; use std::path::Path; -use clap::{App, Arg}; +use clap::{crate_version, App, Arg}; + +pub static BASE_CMD_PARSE_ERROR: i32 = 1; // Config. pub struct Config { @@ -35,15 +38,14 @@ pub mod options { } impl Config { - pub fn from(app_name: &str, options: &clap::ArgMatches) -> Result { + pub fn from(options: &clap::ArgMatches) -> UResult { let file: Option = match options.values_of(options::FILE) { Some(mut values) => { let name = values.next().unwrap(); if let Some(extra_op) = values.next() { - return Err(format!( - "extra operand {}\nTry '{} --help' for more information.", - extra_op.quote(), - app_name + return Err(UUsageError::new( + BASE_CMD_PARSE_ERROR, + format!("extra operand {}", extra_op.quote(),), )); } @@ -51,7 +53,10 @@ impl Config { None } else { if !Path::exists(Path::new(name)) { - return Err(format!("{}: No such file or directory", name.maybe_quote())); + return Err(USimpleError::new( + BASE_CMD_PARSE_ERROR, + format!("{}: No such file or directory", name.maybe_quote()), + )); } Some(name.to_owned()) } @@ -62,8 +67,12 @@ impl Config { let cols = options .value_of(options::WRAP) .map(|num| { - num.parse::() - .map_err(|_| format!("invalid wrap size: {}", num.quote())) + num.parse::().map_err(|_| { + USimpleError::new( + BASE_CMD_PARSE_ERROR, + format!("invalid wrap size: {}", num.quote()), + ) + }) }) .transpose()?; @@ -76,23 +85,17 @@ impl Config { } } -pub fn parse_base_cmd_args( - args: impl uucore::Args, - name: &str, - version: &str, - about: &str, - usage: &str, -) -> Result { - let app = base_app(name, version, about).usage(usage); +pub fn parse_base_cmd_args(args: impl uucore::Args, about: &str, usage: &str) -> UResult { + let app = base_app(about).usage(usage); let arg_list = args .collect_str(InvalidEncodingHandling::ConvertLossy) .accept_any(); - Config::from(name, &app.get_matches_from(arg_list)) + Config::from(&app.get_matches_from(arg_list)) } -pub fn base_app<'a>(name: &str, version: &'a str, about: &'a str) -> App<'static, 'a> { - App::new(name) - .version(version) +pub fn base_app<'a>(about: &'a str) -> App<'static, 'a> { + App::new(uucore::util_name()) + .version(crate_version!()) .about(about) // Format arguments. .arg( @@ -121,14 +124,15 @@ pub fn base_app<'a>(name: &str, version: &'a str, about: &'a str) -> App<'static .arg(Arg::with_name(options::FILE).index(1).multiple(true)) } -pub fn get_input<'a>(config: &Config, stdin_ref: &'a Stdin) -> Box { +pub fn get_input<'a>(config: &Config, stdin_ref: &'a Stdin) -> UResult> { match &config.to_read { Some(name) => { - let file_buf = crash_if_err!(1, File::open(Path::new(name))); - Box::new(BufReader::new(file_buf)) // as Box + let file_buf = + File::open(Path::new(name)).map_err_context(|| name.maybe_quote().to_string())?; + Ok(Box::new(BufReader::new(file_buf))) // as Box } None => { - Box::new(stdin_ref.lock()) // as Box + Ok(Box::new(stdin_ref.lock())) // as Box } } } @@ -139,8 +143,7 @@ pub fn handle_input( line_wrap: Option, ignore_garbage: bool, decode: bool, - name: &str, -) { +) -> UResult<()> { let mut data = Data::new(input, format).ignore_garbage(ignore_garbage); if let Some(wrap) = line_wrap { data = data.line_wrap(wrap); @@ -150,28 +153,25 @@ pub fn handle_input( match data.encode() { Ok(s) => { wrap_print(&data, s); + Ok(()) } - Err(_) => { - eprintln!( - "{}: error: invalid input (length must be multiple of 4 characters)", - name - ); - exit!(1) - } + Err(_) => Err(USimpleError::new( + 1, + "error: invalid input (length must be multiple of 4 characters)", + )), } } else { match data.decode() { Ok(s) => { + // Silent the warning as we want to the error message + #[allow(clippy::question_mark)] if stdout().write_all(&s).is_err() { // on windows console, writing invalid utf8 returns an error - eprintln!("{}: error: Cannot write non-utf8 data", name); - exit!(1) + return Err(USimpleError::new(1, "error: cannot write non-utf8 data")); } + Ok(()) } - Err(_) => { - eprintln!("{}: error: invalid input", name); - exit!(1) - } + Err(_) => Err(USimpleError::new(1, "error: invalid input")), } } } diff --git a/src/uu/base64/Cargo.toml b/src/uu/base64/Cargo.toml index 011964dc1..c8d71b85a 100644 --- a/src/uu/base64/Cargo.toml +++ b/src/uu/base64/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_base64" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "base64 ~ (uutils) decode/encode input (base64-encoding)" @@ -16,9 +16,9 @@ path = "src/base64.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features = ["encoding"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } -uu_base32 = { version=">=0.0.6", package="uu_base32", path="../base32"} +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features = ["encoding"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } +uu_base32 = { version=">=0.0.8", package="uu_base32", path="../base32"} [[bin]] name = "base64" diff --git a/src/uu/base64/src/base64.rs b/src/uu/base64/src/base64.rs index ded157362..c041d6d69 100644 --- a/src/uu/base64/src/base64.rs +++ b/src/uu/base64/src/base64.rs @@ -6,13 +6,10 @@ // For the full copyright and license information, please view the LICENSE file // that was distributed with this source code. -#[macro_use] -extern crate uucore; - use uu_base32::base_common; pub use uu_base32::uu_app; -use uucore::encoding::Format; +use uucore::{encoding::Format, error::UResult}; use std::io::{stdin, Read}; @@ -25,26 +22,22 @@ static ABOUT: &str = " to attempt to recover from any other non-alphabet bytes in the encoded stream. "; -static VERSION: &str = env!("CARGO_PKG_VERSION"); - -static BASE_CMD_PARSE_ERROR: i32 = 1; fn usage() -> String { format!("{0} [OPTION]... [FILE]", uucore::execution_phrase()) } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let format = Format::Base64; let usage = usage(); - let name = uucore::util_name(); - let config_result: Result = - base_common::parse_base_cmd_args(args, name, VERSION, ABOUT, &usage); - let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s)); + + let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?; // Create a reference to stdin so we can return a locked stdin from // parse_base_cmd_args let stdin_raw = stdin(); - let mut input: Box = base_common::get_input(&config, &stdin_raw); + let mut input: Box = base_common::get_input(&config, &stdin_raw)?; base_common::handle_input( &mut input, @@ -52,8 +45,5 @@ pub fn uumain(args: impl uucore::Args) -> i32 { config.wrap_cols, config.ignore_garbage, config.decode, - name, - ); - - 0 + ) } diff --git a/src/uu/basename/Cargo.toml b/src/uu/basename/Cargo.toml index b5b0a462c..b75105790 100644 --- a/src/uu/basename/Cargo.toml +++ b/src/uu/basename/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_basename" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "basename ~ (uutils) display PATHNAME with leading directory components removed" @@ -16,8 +16,8 @@ path = "src/basename.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "basename" diff --git a/src/uu/basenc/Cargo.toml b/src/uu/basenc/Cargo.toml index e8350d83d..165d3d3a0 100644 --- a/src/uu/basenc/Cargo.toml +++ b/src/uu/basenc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_basenc" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "basenc ~ (uutils) decode/encode input" @@ -16,9 +16,9 @@ path = "src/basenc.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features = ["encoding"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } -uu_base32 = { version=">=0.0.6", package="uu_base32", path="../base32"} +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features = ["encoding"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } +uu_base32 = { version=">=0.0.8", package="uu_base32", path="../base32"} [[bin]] name = "basenc" diff --git a/src/uu/basenc/src/basenc.rs b/src/uu/basenc/src/basenc.rs index 86c251ad1..e4b24c351 100644 --- a/src/uu/basenc/src/basenc.rs +++ b/src/uu/basenc/src/basenc.rs @@ -8,13 +8,14 @@ //spell-checker:ignore (args) lsbf msbf -#[macro_use] -extern crate uucore; +use clap::{App, Arg}; +use uu_base32::base_common::{self, Config, BASE_CMD_PARSE_ERROR}; -use clap::{crate_version, App, Arg}; -use uu_base32::base_common::{self, Config}; - -use uucore::{encoding::Format, InvalidEncodingHandling}; +use uucore::{ + encoding::Format, + error::{UResult, UUsageError}, + InvalidEncodingHandling, +}; use std::io::{stdin, Read}; @@ -26,8 +27,6 @@ static ABOUT: &str = " from any other non-alphabet bytes in the encoded stream. "; -static BASE_CMD_PARSE_ERROR: i32 = 1; - const ENCODINGS: &[(&str, Format)] = &[ ("base64", Format::Base64), ("base64url", Format::Base64Url), @@ -47,14 +46,14 @@ fn usage() -> String { } pub fn uu_app() -> App<'static, 'static> { - let mut app = base_common::base_app(uucore::util_name(), crate_version!(), ABOUT); + let mut app = base_common::base_app(ABOUT); for encoding in ENCODINGS { app = app.arg(Arg::with_name(encoding.0).long(encoding.0)); } app } -fn parse_cmd_args(args: impl uucore::Args) -> (Config, Format) { +fn parse_cmd_args(args: impl uucore::Args) -> UResult<(Config, Format)> { let usage = usage(); let matches = uu_app().usage(&usage[..]).get_matches_from( args.collect_str(InvalidEncodingHandling::ConvertLossy) @@ -63,24 +62,19 @@ fn parse_cmd_args(args: impl uucore::Args) -> (Config, Format) { let format = ENCODINGS .iter() .find(|encoding| matches.is_present(encoding.0)) - .unwrap_or_else(|| { - show_usage_error!("missing encoding type"); - std::process::exit(1) - }) + .ok_or_else(|| UUsageError::new(BASE_CMD_PARSE_ERROR, "missing encoding type"))? .1; - ( - Config::from("basenc", &matches).unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s)), - format, - ) + let config = Config::from(&matches)?; + Ok((config, format)) } -pub fn uumain(args: impl uucore::Args) -> i32 { - let name = uucore::util_name(); - let (config, format) = parse_cmd_args(args); +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let (config, format) = parse_cmd_args(args)?; // Create a reference to stdin so we can return a locked stdin from // parse_base_cmd_args let stdin_raw = stdin(); - let mut input: Box = base_common::get_input(&config, &stdin_raw); + let mut input: Box = base_common::get_input(&config, &stdin_raw)?; base_common::handle_input( &mut input, @@ -88,8 +82,5 @@ pub fn uumain(args: impl uucore::Args) -> i32 { config.wrap_cols, config.ignore_garbage, config.decode, - name, - ); - - 0 + ) } diff --git a/src/uu/cat/Cargo.toml b/src/uu/cat/Cargo.toml index d4f137d7e..b6b0165ef 100644 --- a/src/uu/cat/Cargo.toml +++ b/src/uu/cat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cat" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "cat ~ (uutils) concatenate and display input" @@ -18,8 +18,8 @@ path = "src/cat.rs" clap = { version = "2.33", features = ["wrap_help"] } thiserror = "1.0" atty = "0.2" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs", "pipes"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs", "pipes"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(unix)'.dependencies] unix_socket = "0.5.0" diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index baf8af6d5..af84890db 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -12,8 +12,6 @@ #[cfg(unix)] extern crate unix_socket; -#[macro_use] -extern crate uucore; // last synced with: cat (GNU coreutils) 8.13 use clap::{crate_version, App, Arg}; @@ -590,7 +588,7 @@ fn write_tab_to_end(mut in_buf: &[u8], writer: &mut W) -> usize { fn write_nonprint_to_end(in_buf: &[u8], writer: &mut W, tab: &[u8]) -> usize { let mut count = 0; - for byte in in_buf.iter().map(|c| *c) { + for byte in in_buf.iter().copied() { if byte == b'\n' { break; } diff --git a/src/uu/chcon/Cargo.toml b/src/uu/chcon/Cargo.toml index 56fbef9ba..a359f142f 100644 --- a/src/uu/chcon/Cargo.toml +++ b/src/uu/chcon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chcon" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "chcon ~ (uutils) change file security context" diff --git a/src/uu/chgrp/Cargo.toml b/src/uu/chgrp/Cargo.toml index 0d1b7e5aa..acc03472c 100644 --- a/src/uu/chgrp/Cargo.toml +++ b/src/uu/chgrp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chgrp" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "chgrp ~ (uutils) change the group ownership of FILE" @@ -16,8 +16,8 @@ path = "src/chgrp.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "chgrp" diff --git a/src/uu/chgrp/src/chgrp.rs b/src/uu/chgrp/src/chgrp.rs index 1795ad0d5..c70e5e5c7 100644 --- a/src/uu/chgrp/src/chgrp.rs +++ b/src/uu/chgrp/src/chgrp.rs @@ -7,8 +7,6 @@ // spell-checker:ignore (ToDO) COMFOLLOW Chowner RFILE RFILE's derefer dgid nonblank nonprint nonprinting -#[macro_use] -extern crate uucore; use uucore::display::Quotable; pub use uucore::entries; use uucore::error::{FromIo, UResult, USimpleError}; diff --git a/src/uu/chmod/Cargo.toml b/src/uu/chmod/Cargo.toml index df150e0ed..64961e6dd 100644 --- a/src/uu/chmod/Cargo.toml +++ b/src/uu/chmod/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chmod" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "chmod ~ (uutils) change mode of FILE" @@ -17,8 +17,8 @@ path = "src/chmod.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs", "mode"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs", "mode"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } walkdir = "2.2" [[bin]] diff --git a/src/uu/chmod/src/chmod.rs b/src/uu/chmod/src/chmod.rs index e25202fbe..68c55b4cb 100644 --- a/src/uu/chmod/src/chmod.rs +++ b/src/uu/chmod/src/chmod.rs @@ -57,7 +57,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { // 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 mode_had_minus_prefix = mode::strip_minus_from_mode(&mut args); let usage = usage(); let after_help = get_long_usage(); @@ -180,30 +180,6 @@ pub fn uu_app() -> App<'static, 'static> { ) } -// Iterate 'args' and delete the first occurrence -// of a prefix '-' if it's associated with MODE -// e.g. "chmod -v -xw -R FILE" -> "chmod -v xw -R FILE" -pub fn strip_minus_from_mode(args: &mut Vec) -> bool { - for arg in args { - if arg == "--" { - break; - } - if arg.starts_with('-') { - if let Some(second) = arg.chars().nth(1) { - match second { - 'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => { - // TODO: use strip_prefix() once minimum rust version reaches 1.45.0 - *arg = arg[1..arg.len()].to_string(); - return true; - } - _ => {} - } - } - } - } - false -} - struct Chmoder { changes: bool, quiet: bool, diff --git a/src/uu/chown/Cargo.toml b/src/uu/chown/Cargo.toml index e6dc7d4fe..20381c660 100644 --- a/src/uu/chown/Cargo.toml +++ b/src/uu/chown/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chown" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "chown ~ (uutils) change the ownership of FILE" @@ -16,8 +16,8 @@ path = "src/chown.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "chown" diff --git a/src/uu/chown/src/chown.rs b/src/uu/chown/src/chown.rs index 1cd71d3f5..f24c4ec89 100644 --- a/src/uu/chown/src/chown.rs +++ b/src/uu/chown/src/chown.rs @@ -7,8 +7,6 @@ // spell-checker:ignore (ToDO) COMFOLLOW Passwd RFILE RFILE's derefer dgid duid groupname -#[macro_use] -extern crate uucore; use uucore::display::Quotable; pub use uucore::entries::{self, Group, Locate, Passwd}; use uucore::perms::{chown_base, options, IfFrom}; diff --git a/src/uu/chroot/Cargo.toml b/src/uu/chroot/Cargo.toml index a808a717b..362e43b59 100644 --- a/src/uu/chroot/Cargo.toml +++ b/src/uu/chroot/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chroot" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "chroot ~ (uutils) run COMMAND under a new root directory" @@ -16,8 +16,8 @@ path = "src/chroot.rs" [dependencies] clap= "2.33" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "chroot" diff --git a/src/uu/chroot/src/chroot.rs b/src/uu/chroot/src/chroot.rs index 40799d009..55097c1bb 100644 --- a/src/uu/chroot/src/chroot.rs +++ b/src/uu/chroot/src/chroot.rs @@ -67,7 +67,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { // TODO: refactor the args and command matching // See: https://github.com/uutils/coreutils/pull/2365#discussion_r647849967 let command: Vec<&str> = match commands.len() { - 1 => { + 0 => { let shell: &str = match user_shell { Err(_) => default_shell, Ok(ref s) => s.as_ref(), @@ -77,12 +77,28 @@ pub fn uumain(args: impl uucore::Args) -> i32 { _ => commands, }; + assert!(!command.is_empty()); + let chroot_command = command[0]; + let chroot_args = &command[1..]; + + // NOTE: Tests can only trigger code beyond this point if they're invoked with root permissions set_context(newroot, &matches); - let pstatus = Command::new(command[0]) - .args(&command[1..]) + let pstatus = Command::new(chroot_command) + .args(chroot_args) .status() - .unwrap_or_else(|e| crash!(1, "Cannot exec: {}", e)); + .unwrap_or_else(|e| { + // TODO: Exit status: + // 125 if chroot itself fails + // 126 if command is found but cannot be invoked + // 127 if command cannot be found + crash!( + 1, + "failed to run command {}: {}", + command[0].to_string().quote(), + e + ) + }); if pstatus.success() { 0 diff --git a/src/uu/cksum/Cargo.toml b/src/uu/cksum/Cargo.toml index 287a2285f..b7f81d74b 100644 --- a/src/uu/cksum/Cargo.toml +++ b/src/uu/cksum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cksum" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "cksum ~ (uutils) display CRC and size of input" @@ -17,8 +17,8 @@ path = "src/cksum.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "cksum" diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index e682aa70c..92853a3e8 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -25,60 +25,15 @@ const NAME: &str = "cksum"; const SYNTAX: &str = "[OPTIONS] [FILE]..."; const SUMMARY: &str = "Print CRC and size for each file"; -// this is basically a hack to get "loops" to work on Rust 1.33. Once we update to Rust 1.46 or -// greater, we can just use while loops -macro_rules! unroll { - (256, |$i:ident| $s:expr) => {{ - unroll!(@ 32, 0 * 32, $i, $s); - unroll!(@ 32, 1 * 32, $i, $s); - unroll!(@ 32, 2 * 32, $i, $s); - unroll!(@ 32, 3 * 32, $i, $s); - unroll!(@ 32, 4 * 32, $i, $s); - unroll!(@ 32, 5 * 32, $i, $s); - unroll!(@ 32, 6 * 32, $i, $s); - unroll!(@ 32, 7 * 32, $i, $s); - }}; - (8, |$i:ident| $s:expr) => {{ - unroll!(@ 8, 0, $i, $s); - }}; - - (@ 32, $start:expr, $i:ident, $s:expr) => {{ - unroll!(@ 8, $start + 0 * 8, $i, $s); - unroll!(@ 8, $start + 1 * 8, $i, $s); - unroll!(@ 8, $start + 2 * 8, $i, $s); - unroll!(@ 8, $start + 3 * 8, $i, $s); - }}; - (@ 8, $start:expr, $i:ident, $s:expr) => {{ - unroll!(@ 4, $start, $i, $s); - unroll!(@ 4, $start + 4, $i, $s); - }}; - (@ 4, $start:expr, $i:ident, $s:expr) => {{ - unroll!(@ 2, $start, $i, $s); - unroll!(@ 2, $start + 2, $i, $s); - }}; - (@ 2, $start:expr, $i:ident, $s:expr) => {{ - unroll!(@ 1, $start, $i, $s); - unroll!(@ 1, $start + 1, $i, $s); - }}; - (@ 1, $start:expr, $i:ident, $s:expr) => {{ - let $i = $start; - let _ = $s; - }}; -} - const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] { let mut table = [0; CRC_TABLE_LEN]; - // NOTE: works on Rust 1.46 - //let mut i = 0; - //while i < CRC_TABLE_LEN { - // table[i] = crc_entry(i as u8) as u32; - // - // i += 1; - //} - unroll!(256, |i| { + let mut i = 0; + while i < CRC_TABLE_LEN { table[i] = crc_entry(i as u8) as u32; - }); + + i += 1; + } table } @@ -86,19 +41,8 @@ const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] { const fn crc_entry(input: u8) -> u32 { let mut crc = (input as u32) << 24; - // NOTE: this does not work on Rust 1.33, but *does* on 1.46 - //let mut i = 0; - //while i < 8 { - // if crc & 0x8000_0000 != 0 { - // crc <<= 1; - // crc ^= 0x04c1_1db7; - // } else { - // crc <<= 1; - // } - // - // i += 1; - //} - unroll!(8, |_i| { + let mut i = 0; + while i < 8 { let if_condition = crc & 0x8000_0000; let if_body = (crc << 1) ^ 0x04c1_1db7; let else_body = crc << 1; @@ -108,7 +52,8 @@ const fn crc_entry(input: u8) -> u32 { let condition_table = [else_body, if_body]; crc = condition_table[(if_condition != 0) as usize]; - }); + i += 1; + } crc } @@ -148,6 +93,8 @@ fn cksum(fname: &str) -> io::Result<(u32, usize)> { "Is a directory", )); }; + // Silent the warning as we want to the error message + #[allow(clippy::question_mark)] if path.metadata().is_err() { return Err(std::io::Error::new( io::ErrorKind::NotFound, diff --git a/src/uu/comm/Cargo.toml b/src/uu/comm/Cargo.toml index e44c3511c..abcbff57b 100644 --- a/src/uu/comm/Cargo.toml +++ b/src/uu/comm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_comm" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "comm ~ (uutils) compare sorted inputs" @@ -17,8 +17,8 @@ path = "src/comm.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "comm" diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index 62aef932b..891bf0244 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cp" -version = "0.0.7" +version = "0.0.8" authors = [ "Jordy Dickinson ", "Joshua S. Miller ", @@ -24,8 +24,8 @@ filetime = "0.2" libc = "0.2.85" quick-error = "1.2.3" selinux = { version="0.2.3", optional=true } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs", "perms", "mode"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries", "fs", "perms", "mode"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } walkdir = "2.2" [target.'cfg(target_os = "linux")'.dependencies] diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index cd33f9fa6..518a2262c 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -49,6 +49,7 @@ use std::path::{Path, PathBuf, StripPrefixError}; use std::str::FromStr; use std::string::ToString; use uucore::backup_control::{self, BackupMode}; +use uucore::error::{set_exit_code, ExitCode, UError, UResult}; use uucore::fs::{canonicalize, MissingHandling, ResolveMode}; use walkdir::WalkDir; @@ -105,6 +106,12 @@ quick_error! { } } +impl UError for Error { + fn code(&self) -> i32 { + EXIT_ERR + } +} + /// Continue next iteration of loop if result of expression is error macro_rules! or_continue( ($expr:expr) => (match $expr { @@ -220,7 +227,6 @@ pub struct Options { static ABOUT: &str = "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY."; static LONG_HELP: &str = ""; -static EXIT_OK: i32 = 0; static EXIT_ERR: i32 = 1; fn usage() -> String { @@ -446,7 +452,8 @@ pub fn uu_app() -> App<'static, 'static> { .multiple(true)) } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let usage = usage(); let matches = uu_app() .after_help(&*format!( @@ -457,11 +464,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .usage(&usage[..]) .get_matches_from(args); - let options = crash_if_err!(EXIT_ERR, Options::from_matches(&matches)); + let options = Options::from_matches(&matches)?; if options.overwrite == OverwriteMode::NoClobber && options.backup != BackupMode::NoBackup { show_usage_error!("options --backup and --no-clobber are mutually exclusive"); - return 1; + return Err(ExitCode(EXIT_ERR).into()); } let paths: Vec = matches @@ -469,7 +476,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .map(|v| v.map(ToString::to_string).collect()) .unwrap_or_default(); - let (sources, target) = crash_if_err!(EXIT_ERR, parse_path_args(&paths, &options)); + let (sources, target) = parse_path_args(&paths, &options)?; if let Err(error) = copy(&sources, &target, &options) { match error { @@ -479,10 +486,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { // Else we caught a fatal bubbled-up error, log it to stderr _ => show_error!("{}", error), }; - return EXIT_ERR; + set_exit_code(EXIT_ERR); } - EXIT_OK + Ok(()) } impl ClobberMode { @@ -1124,7 +1131,7 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu let xattrs = xattr::list(source)?; for attr in xattrs { if let Some(attr_value) = xattr::get(source, attr.clone())? { - crash_if_err!(EXIT_ERR, xattr::set(dest, attr, &attr_value[..])); + xattr::set(dest, attr, &attr_value[..])?; } } } diff --git a/src/uu/csplit/Cargo.toml b/src/uu/csplit/Cargo.toml index 40d4eebfa..b76e942ee 100644 --- a/src/uu/csplit/Cargo.toml +++ b/src/uu/csplit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_csplit" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "csplit ~ (uutils) Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output" @@ -18,8 +18,8 @@ path = "src/csplit.rs" clap = { version = "2.33", features = ["wrap_help"] } thiserror = "1.0" regex = "1.0.0" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries", "fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries", "fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "csplit" diff --git a/src/uu/csplit/src/csplit.rs b/src/uu/csplit/src/csplit.rs index dbf65b71d..0d99154df 100644 --- a/src/uu/csplit/src/csplit.rs +++ b/src/uu/csplit/src/csplit.rs @@ -320,18 +320,19 @@ impl<'a> SplitWriter<'a> { let l = line?; match n.cmp(&(&ln + 1)) { Ordering::Less => { - if input_iter.add_line_to_buffer(ln, l).is_some() { - panic!("the buffer is big enough to contain 1 line"); - } + assert!( + input_iter.add_line_to_buffer(ln, l).is_none(), + "the buffer is big enough to contain 1 line" + ); ret = Ok(()); break; } Ordering::Equal => { - if !self.options.suppress_matched - && input_iter.add_line_to_buffer(ln, l).is_some() - { - panic!("the buffer is big enough to contain 1 line"); - } + assert!( + self.options.suppress_matched + || input_iter.add_line_to_buffer(ln, l).is_none(), + "the buffer is big enough to contain 1 line" + ); ret = Ok(()); break; } @@ -378,9 +379,10 @@ impl<'a> SplitWriter<'a> { match (self.options.suppress_matched, offset) { // no offset, add the line to the next split (false, 0) => { - if input_iter.add_line_to_buffer(ln, l).is_some() { - panic!("the buffer is big enough to contain 1 line"); - } + assert!( + input_iter.add_line_to_buffer(ln, l).is_none(), + "the buffer is big enough to contain 1 line" + ); } // a positive offset, some more lines need to be added to the current split (false, _) => self.writeln(l)?, @@ -425,9 +427,10 @@ impl<'a> SplitWriter<'a> { if !self.options.suppress_matched { // add 1 to the buffer size to make place for the matched line input_iter.set_size_of_buffer(offset_usize + 1); - if input_iter.add_line_to_buffer(ln, l).is_some() { - panic!("should be big enough to hold every lines"); - } + assert!( + input_iter.add_line_to_buffer(ln, l).is_none(), + "should be big enough to hold every lines" + ); } self.finish_split(); if input_iter.buffer_len() < offset_usize { diff --git a/src/uu/cut/Cargo.toml b/src/uu/cut/Cargo.toml index c49450251..991e3c449 100644 --- a/src/uu/cut/Cargo.toml +++ b/src/uu/cut/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cut" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "cut ~ (uutils) display byte/field columns of input lines" @@ -16,8 +16,8 @@ path = "src/cut.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } memchr = "2" bstr = "0.2" atty = "0.2" diff --git a/src/uu/date/Cargo.toml b/src/uu/date/Cargo.toml index d2af8c4f1..b1077fbe1 100644 --- a/src/uu/date/Cargo.toml +++ b/src/uu/date/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_date" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "date ~ (uutils) display or set the current time" @@ -17,8 +17,8 @@ path = "src/date.rs" [dependencies] chrono = "0.4.4" clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/uu/dd/Cargo.toml b/src/uu/dd/Cargo.toml index 007ebb8ff..e26c141cb 100644 --- a/src/uu/dd/Cargo.toml +++ b/src/uu/dd/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_dd" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "dd ~ (uutils) copy and convert files" diff --git a/src/uu/dd/src/parseargs/unit_tests.rs b/src/uu/dd/src/parseargs/unit_tests.rs index b898f1e5d..21900ee49 100644 --- a/src/uu/dd/src/parseargs/unit_tests.rs +++ b/src/uu/dd/src/parseargs/unit_tests.rs @@ -35,12 +35,11 @@ fn unimplemented_flags_should_error_non_linux() { } } - if !succeeded.is_empty() { - panic!( - "The following flags did not panic as expected: {:?}", - succeeded - ); - } + assert!( + succeeded.is_empty(), + "The following flags did not panic as expected: {:?}", + succeeded + ); } #[test] @@ -64,12 +63,11 @@ fn unimplemented_flags_should_error() { } } - if !succeeded.is_empty() { - panic!( - "The following flags did not panic as expected: {:?}", - succeeded - ); - } + assert!( + succeeded.is_empty(), + "The following flags did not panic as expected: {:?}", + succeeded + ); } #[test] diff --git a/src/uu/df/Cargo.toml b/src/uu/df/Cargo.toml index 6979a79b4..9486640d0 100644 --- a/src/uu/df/Cargo.toml +++ b/src/uu/df/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_df" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "df ~ (uutils) display file system information" @@ -17,8 +17,8 @@ path = "src/df.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } number_prefix = "0.4" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["libc", "fsext"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["libc", "fsext"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "df" diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index 310d3c664..2f703542c 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -6,8 +6,6 @@ // For the full copyright and license information, please view the LICENSE file // that was distributed with this source code. -#[macro_use] -extern crate uucore; use uucore::error::UError; use uucore::error::UResult; #[cfg(unix)] diff --git a/src/uu/dircolors/Cargo.toml b/src/uu/dircolors/Cargo.toml index ad95564f3..0bf53d91a 100644 --- a/src/uu/dircolors/Cargo.toml +++ b/src/uu/dircolors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_dircolors" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "dircolors ~ (uutils) display commands to set LS_COLORS" @@ -17,8 +17,8 @@ path = "src/dircolors.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } glob = "0.3.0" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "dircolors" diff --git a/src/uu/dirname/Cargo.toml b/src/uu/dirname/Cargo.toml index bd9e449d7..7946459f3 100644 --- a/src/uu/dirname/Cargo.toml +++ b/src/uu/dirname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_dirname" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "dirname ~ (uutils) display parent directory of PATHNAME" @@ -17,8 +17,8 @@ path = "src/dirname.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "dirname" diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index 601d93ac0..129c9369e 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -5,9 +5,6 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use std::path::Path; use uucore::display::print_verbatim; diff --git a/src/uu/du/Cargo.toml b/src/uu/du/Cargo.toml index dfc50f7a6..c9da0462c 100644 --- a/src/uu/du/Cargo.toml +++ b/src/uu/du/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_du" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "du ~ (uutils) display disk usage" @@ -17,8 +17,8 @@ path = "src/du.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } chrono = "0.4" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(target_os = "windows")'.dependencies] winapi = { version="0.3", features=[] } diff --git a/src/uu/echo/Cargo.toml b/src/uu/echo/Cargo.toml index 60a547e21..05dd1eba1 100644 --- a/src/uu/echo/Cargo.toml +++ b/src/uu/echo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_echo" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "echo ~ (uutils) display TEXT" @@ -16,8 +16,8 @@ path = "src/echo.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "echo" diff --git a/src/uu/echo/src/echo.rs b/src/uu/echo/src/echo.rs index 601fd8d48..a0e6c0d9c 100644 --- a/src/uu/echo/src/echo.rs +++ b/src/uu/echo/src/echo.rs @@ -6,9 +6,6 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use std::io::{self, Write}; use std::iter::Peekable; diff --git a/src/uu/env/Cargo.toml b/src/uu/env/Cargo.toml index c368cfbac..374a4eda9 100644 --- a/src/uu/env/Cargo.toml +++ b/src/uu/env/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_env" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND" @@ -18,8 +18,8 @@ path = "src/env.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" rust-ini = "0.17.0" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "env" diff --git a/src/uu/expand/Cargo.toml b/src/uu/expand/Cargo.toml index e9b2cc747..efd338dab 100644 --- a/src/uu/expand/Cargo.toml +++ b/src/uu/expand/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_expand" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "expand ~ (uutils) convert input tabs to spaces" @@ -17,8 +17,8 @@ path = "src/expand.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } unicode-width = "0.1.5" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "expand" diff --git a/src/uu/expr/Cargo.toml b/src/uu/expr/Cargo.toml index 035f00721..90a53f2ce 100644 --- a/src/uu/expr/Cargo.toml +++ b/src/uu/expr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_expr" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "expr ~ (uutils) display the value of EXPRESSION" @@ -20,8 +20,8 @@ libc = "0.2.42" num-bigint = "0.4.0" num-traits = "0.2.14" onig = "~4.3.2" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "expr" diff --git a/src/uu/expr/src/expr.rs b/src/uu/expr/src/expr.rs index eaf329bc5..6e2a8701a 100644 --- a/src/uu/expr/src/expr.rs +++ b/src/uu/expr/src/expr.rs @@ -5,9 +5,6 @@ //* For the full copyright and license information, please view the LICENSE //* file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use uucore::error::{UResult, USimpleError}; use uucore::InvalidEncodingHandling; diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index 9d62e5f2b..2d2fa236b 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_factor" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "factor ~ (uutils) display the prime factors of each NUMBER" @@ -20,7 +20,7 @@ num-traits = "0.2.13" # Needs at least version 0.2.13 for "OverflowingAdd" rand = { version = "0.7", features = ["small_rng"] } smallvec = { version = "0.6.14, < 1.0" } uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore" } -uucore_procs = { version=">=0.0.6", package = "uucore_procs", path = "../../uucore_procs" } +uucore_procs = { version=">=0.0.7", package = "uucore_procs", path = "../../uucore_procs" } clap = { version = "2.33", features = ["wrap_help"] } [dev-dependencies] diff --git a/src/uu/false/Cargo.toml b/src/uu/false/Cargo.toml index d6b4b7d6d..2a725e2b0 100644 --- a/src/uu/false/Cargo.toml +++ b/src/uu/false/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_false" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "false ~ (uutils) do nothing and fail" @@ -16,8 +16,8 @@ path = "src/false.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "false" diff --git a/src/uu/false/src/false.rs b/src/uu/false/src/false.rs index 88ec1af06..783c7fa0d 100644 --- a/src/uu/false/src/false.rs +++ b/src/uu/false/src/false.rs @@ -5,9 +5,6 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use clap::App; use uucore::error::UResult; diff --git a/src/uu/fmt/Cargo.toml b/src/uu/fmt/Cargo.toml index 75b81c354..a4700cb5e 100644 --- a/src/uu/fmt/Cargo.toml +++ b/src/uu/fmt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_fmt" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "fmt ~ (uutils) reformat each paragraph of input" @@ -18,8 +18,8 @@ path = "src/fmt.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" unicode-width = "0.1.5" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "fmt" diff --git a/src/uu/fold/Cargo.toml b/src/uu/fold/Cargo.toml index 7ec886264..ce2aeead4 100644 --- a/src/uu/fold/Cargo.toml +++ b/src/uu/fold/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_fold" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "fold ~ (uutils) wrap each line of input" @@ -16,8 +16,8 @@ path = "src/fold.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "fold" diff --git a/src/uu/groups/Cargo.toml b/src/uu/groups/Cargo.toml index c32153f17..6ac210692 100644 --- a/src/uu/groups/Cargo.toml +++ b/src/uu/groups/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_groups" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "groups ~ (uutils) display group memberships for USERNAME" @@ -15,8 +15,8 @@ edition = "2018" path = "src/groups.rs" [dependencies] -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries", "process"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries", "process"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } clap = { version = "2.33", features = ["wrap_help"] } [[bin]] diff --git a/src/uu/hashsum/Cargo.toml b/src/uu/hashsum/Cargo.toml index 7cb88dede..67b0f9e02 100644 --- a/src/uu/hashsum/Cargo.toml +++ b/src/uu/hashsum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_hashsum" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "hashsum ~ (uutils) display or check input digests" @@ -27,8 +27,8 @@ sha1 = "0.6.0" sha2 = "0.6.0" sha3 = "0.6.0" blake2b_simd = "0.5.11" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "hashsum" diff --git a/src/uu/hashsum/src/digest.rs b/src/uu/hashsum/src/digest.rs index 531dc7e4f..61f425662 100644 --- a/src/uu/hashsum/src/digest.rs +++ b/src/uu/hashsum/src/digest.rs @@ -189,13 +189,31 @@ pub struct DigestWriter<'a> { /// "\n" before passing input bytes to the [`digest`]. #[allow(dead_code)] binary: bool, - // TODO This is dead code only on non-Windows operating systems. It - // might be better to use a `#[cfg(windows)]` guard here. + + /// Whether the previous + #[allow(dead_code)] + was_last_character_carriage_return: bool, + // TODO These are dead code only on non-Windows operating systems. + // It might be better to use a `#[cfg(windows)]` guard here. } impl<'a> DigestWriter<'a> { pub fn new(digest: &'a mut Box, binary: bool) -> DigestWriter { - DigestWriter { digest, binary } + let was_last_character_carriage_return = false; + DigestWriter { + digest, + binary, + was_last_character_carriage_return, + } + } + + pub fn finalize(&mut self) -> bool { + if self.was_last_character_carriage_return { + self.digest.input(&[b'\r']); + true + } else { + false + } } } @@ -213,22 +231,40 @@ impl<'a> Write for DigestWriter<'a> { return Ok(buf.len()); } - // In Windows text mode, replace each occurrence of "\r\n" - // with "\n". + // The remaining code handles Windows text mode, where we must + // replace each occurrence of "\r\n" with "\n". // - // Find all occurrences of "\r\n", inputting the slice just - // before the "\n" in the previous instance of "\r\n" and - // the beginning of this "\r\n". - // - // FIXME This fails if one call to `write()` ends with the - // "\r" and the next call to `write()` begins with the "\n". + // First, if the last character written was "\r" and the first + // character in the current buffer to write is not "\n", then we + // need to write the "\r" that we buffered from the previous + // call to `write()`. let n = buf.len(); + if self.was_last_character_carriage_return && n > 0 && buf[0] != b'\n' { + self.digest.input(&[b'\r']); + } + + // Next, find all occurrences of "\r\n", inputting the slice + // just before the "\n" in the previous instance of "\r\n" and + // the beginning of this "\r\n". let mut i_prev = 0; for i in memmem::find_iter(buf, b"\r\n") { self.digest.input(&buf[i_prev..i]); i_prev = i + 1; } - self.digest.input(&buf[i_prev..n]); + + // Finally, check whether the last character is "\r". If so, + // buffer it until we know that the next character is not "\n", + // which can only be known on the next call to `write()`. + // + // This all assumes that `write()` will be called on adjacent + // blocks of the input. + if n > 0 && buf[n - 1] == b'\r' { + self.was_last_character_carriage_return = true; + self.digest.input(&buf[i_prev..n - 1]); + } else { + self.was_last_character_carriage_return = false; + self.digest.input(&buf[i_prev..n]); + } // Even though we dropped a "\r" for each "\r\n" we found, we // still report the number of bytes written as `n`. This is @@ -243,3 +279,36 @@ impl<'a> Write for DigestWriter<'a> { Ok(()) } } + +#[cfg(test)] +mod tests { + + /// Test for replacing a "\r\n" sequence with "\n" when the "\r" is + /// at the end of one block and the "\n" is at the beginning of the + /// next block, when reading in blocks. + #[cfg(windows)] + #[test] + fn test_crlf_across_blocks() { + use std::io::Write; + + use crate::digest::Digest; + use crate::digest::DigestWriter; + + // Writing "\r" in one call to `write()`, and then "\n" in another. + let mut digest = Box::new(md5::Context::new()) as Box; + let mut writer_crlf = DigestWriter::new(&mut digest, false); + writer_crlf.write_all(&[b'\r']).unwrap(); + writer_crlf.write_all(&[b'\n']).unwrap(); + writer_crlf.finalize(); + let result_crlf = digest.result_str(); + + // We expect "\r\n" to be replaced with "\n" in text mode on Windows. + let mut digest = Box::new(md5::Context::new()) as Box; + let mut writer_lf = DigestWriter::new(&mut digest, false); + writer_lf.write_all(&[b'\n']).unwrap(); + writer_lf.finalize(); + let result_lf = digest.result_str(); + + assert_eq!(result_crlf, result_lf); + } +} diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 4186043f5..07070ed1b 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -611,8 +611,16 @@ fn digest_reader( // If `binary` is `false` and the operating system is Windows, then // `DigestWriter` replaces "\r\n" with "\n" before it writes the // bytes into `digest`. Otherwise, it just inserts the bytes as-is. + // + // In order to support replacing "\r\n", we must call `finalize()` + // in order to support the possibility that the last character read + // from the reader was "\r". (This character gets buffered by + // `DigestWriter` and only written if the following character is + // "\n". But when "\r" is the last character read, we need to force + // it to be written.) let mut digest_writer = DigestWriter::new(digest, binary); std::io::copy(reader, &mut digest_writer)?; + digest_writer.finalize(); if digest.output_bits() > 0 { Ok(digest.result_str()) diff --git a/src/uu/head/BENCHMARKING.md b/src/uu/head/BENCHMARKING.md new file mode 100644 index 000000000..49574eb79 --- /dev/null +++ b/src/uu/head/BENCHMARKING.md @@ -0,0 +1,41 @@ +# Benchmarking to measure performance + +To compare the performance of the `uutils` version of `head` with the +GNU version of `head`, you can use a benchmarking tool like +[hyperfine][0]. On Ubuntu 18.04 or later, you can install `hyperfine` by +running + + sudo apt-get install hyperfine + +Next, build the `head` binary under the release profile: + + cargo build --release -p uu_head + +Now, get a text file to test `head` on. I used the *Complete Works of +William Shakespeare*, which is in the public domain in the United States +and most other parts of the world. + + wget -O shakespeare.txt https://www.gutenberg.org/files/100/100-0.txt + +This particular file has about 170,000 lines, each of which is no longer +than 96 characters: + + $ wc -lL shakespeare.txt + 170592 96 shakespeare.txt + +You could use files of different shapes and sizes to test the +performance of `head` in different situations. For a larger file, you +could download a [database dump of Wikidata][1] or some related files +that the Wikimedia project provides. For example, [this file][2] +contains about 130 million lines. + +Finally, you can compare the performance of the two versions of `head` +by running, for example, + + hyperfine \ + "head -n 100000 shakespeare.txt" \ + "target/release/head -n 100000 shakespeare.txt" + +[0]: https://github.com/sharkdp/hyperfine +[1]: https://www.wikidata.org/wiki/Wikidata:Database_download +[2]: https://dumps.wikimedia.org/wikidatawiki/20211001/wikidatawiki-20211001-pages-logging.xml.gz diff --git a/src/uu/head/Cargo.toml b/src/uu/head/Cargo.toml index 4fa4c0c81..aa32a899a 100644 --- a/src/uu/head/Cargo.toml +++ b/src/uu/head/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_head" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "head ~ (uutils) display the first lines of input" @@ -16,8 +16,9 @@ path = "src/head.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["ringbuffer"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +memchr = "2" +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["ringbuffer"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "head" diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index ead734088..e3325d084 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -3,23 +3,24 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -// spell-checker:ignore (vars) zlines +// spell-checker:ignore (vars) zlines BUFWRITER use clap::{crate_version, App, Arg}; use std::convert::TryFrom; use std::ffi::OsString; -use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; +use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write}; use uucore::display::Quotable; -use uucore::{crash, show_error_custom_description}; +use uucore::error::{UResult, USimpleError}; +use uucore::show_error_custom_description; -const EXIT_FAILURE: i32 = 1; -const EXIT_SUCCESS: i32 = 0; const BUF_SIZE: usize = 65536; +/// The capacity in bytes for buffered writers. +const BUFWRITER_CAPACITY: usize = 16_384; // 16 kilobytes + const ABOUT: &str = "\ Print the first 10 lines of each FILE to standard output.\n\ With more than one FILE, precede each with a header giving the file name.\n\ - \n\ With no FILE, or when FILE is -, read standard input.\n\ \n\ Mandatory arguments to long flags are mandatory for short flags too.\ @@ -36,10 +37,10 @@ mod options { } mod lines; mod parse; -mod split; mod take; use lines::zlines; use take::take_all_but; +use take::take_lines; pub fn uu_app() -> App<'static, 'static> { App::new(uucore::util_name()) @@ -108,6 +109,12 @@ enum Modes { Bytes(usize), } +impl Default for Modes { + fn default() -> Self { + Modes::Lines(10) + } +} + fn parse_mode(src: &str, closure: F) -> Result<(Modes, bool), String> where F: FnOnce(usize) -> Modes, @@ -144,7 +151,7 @@ fn arg_iterate<'a>( } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Default)] struct HeadOptions { pub quiet: bool, pub verbose: bool, @@ -155,22 +162,11 @@ struct HeadOptions { } impl HeadOptions { - pub fn new() -> HeadOptions { - HeadOptions { - quiet: false, - verbose: false, - zeroed: false, - all_but_last: false, - mode: Modes::Lines(10), - files: Vec::new(), - } - } - ///Construct options from matches pub fn get_from(args: impl uucore::Args) -> Result { let matches = uu_app().get_matches_from(arg_iterate(args)?); - let mut options = HeadOptions::new(); + let mut options: HeadOptions = Default::default(); options.quiet = matches.is_present(options::QUIET_NAME); options.verbose = matches.is_present(options::VERBOSE_NAME); @@ -197,12 +193,6 @@ impl HeadOptions { Ok(options) } } -// to make clippy shut up -impl Default for HeadOptions { - fn default() -> Self { - Self::new() - } -} fn read_n_bytes(input: R, n: usize) -> std::io::Result<()> where @@ -221,26 +211,18 @@ where } fn read_n_lines(input: &mut impl std::io::BufRead, n: usize, zero: bool) -> std::io::Result<()> { - if n == 0 { - return Ok(()); - } + // Read the first `n` lines from the `input` reader. + let separator = if zero { b'\0' } else { b'\n' }; + let mut reader = take_lines(input, n, separator); + + // Write those bytes to `stdout`. let stdout = std::io::stdout(); - let mut stdout = stdout.lock(); - let mut lines = 0usize; - split::walk_lines(input, zero, |e| match e { - split::Event::Data(dat) => { - stdout.write_all(dat)?; - Ok(true) - } - split::Event::Line => { - lines += 1; - if lines == n { - Ok(false) - } else { - Ok(true) - } - } - }) + let stdout = stdout.lock(); + let mut writer = BufWriter::with_capacity(BUFWRITER_CAPACITY, stdout); + + io::copy(&mut reader, &mut writer)?; + + Ok(()) } fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: usize) -> std::io::Result<()> { @@ -384,7 +366,7 @@ fn head_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Resul } } -fn uu_head(options: &HeadOptions) -> Result<(), u32> { +fn uu_head(options: &HeadOptions) -> UResult<()> { let mut error_count = 0; let mut first = true; for file in &options.files { @@ -457,23 +439,21 @@ fn uu_head(options: &HeadOptions) -> Result<(), u32> { first = false; } if error_count > 0 { - Err(error_count) + Err(USimpleError::new(1, "")) } else { Ok(()) } } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = match HeadOptions::get_from(args) { Ok(o) => o, Err(s) => { - crash!(EXIT_FAILURE, "{}", s); + return Err(USimpleError::new(1, s)); } }; - match uu_head(&args) { - Ok(_) => EXIT_SUCCESS, - Err(_) => EXIT_FAILURE, - } + uu_head(&args) } #[cfg(test)] @@ -523,17 +503,13 @@ mod tests { assert!(options("-c IsThisJustFantasy").is_err()); } #[test] - #[allow(clippy::bool_comparison)] fn test_options_correct_defaults() { - let opts = HeadOptions::new(); - let opts2: HeadOptions = Default::default(); + let opts: HeadOptions = Default::default(); - assert_eq!(opts, opts2); - - assert!(opts.verbose == false); - assert!(opts.quiet == false); - assert!(opts.zeroed == false); - assert!(opts.all_but_last == false); + assert!(!opts.verbose); + assert!(!opts.quiet); + assert!(!opts.zeroed); + assert!(!opts.all_but_last); assert_eq!(opts.mode, Modes::Lines(10)); assert!(opts.files.is_empty()); } diff --git a/src/uu/head/src/split.rs b/src/uu/head/src/split.rs deleted file mode 100644 index 9e9a0c685..000000000 --- a/src/uu/head/src/split.rs +++ /dev/null @@ -1,60 +0,0 @@ -#[derive(Debug)] -pub enum Event<'a> { - Data(&'a [u8]), - Line, -} -/// Loops over the lines read from a BufRead. -/// # Arguments -/// * `input` the ReadBuf to read from -/// * `zero` whether to use 0u8 as a line delimiter -/// * `on_event` a closure receiving some bytes read in a slice, or -/// event signalling a line was just read. -/// this is guaranteed to be signalled *directly* after the -/// slice containing the (CR on win)LF / 0 is passed -/// -/// Return whether to continue -pub fn walk_lines( - input: &mut impl std::io::BufRead, - zero: bool, - mut on_event: F, -) -> std::io::Result<()> -where - F: FnMut(Event) -> std::io::Result, -{ - let mut buffer = [0u8; super::BUF_SIZE]; - loop { - let read = loop { - match input.read(&mut buffer) { - Ok(n) => break n, - Err(e) => match e.kind() { - std::io::ErrorKind::Interrupted => {} - _ => return Err(e), - }, - } - }; - if read == 0 { - return Ok(()); - } - let mut base = 0usize; - for (i, byte) in buffer[..read].iter().enumerate() { - match byte { - b'\n' if !zero => { - on_event(Event::Data(&buffer[base..=i]))?; - base = i + 1; - if !on_event(Event::Line)? { - return Ok(()); - } - } - 0u8 if zero => { - on_event(Event::Data(&buffer[base..=i]))?; - base = i + 1; - if !on_event(Event::Line)? { - return Ok(()); - } - } - _ => {} - } - } - on_event(Event::Data(&buffer[base..read]))?; - } -} diff --git a/src/uu/head/src/take.rs b/src/uu/head/src/take.rs index 94fa012be..5f4c29b65 100644 --- a/src/uu/head/src/take.rs +++ b/src/uu/head/src/take.rs @@ -1,4 +1,8 @@ //! Take all but the last elements of an iterator. +use std::io::Read; + +use memchr::memchr_iter; + use uucore::ringbuffer::RingBuffer; /// Create an iterator over all but the last `n` elements of `iter`. @@ -58,10 +62,63 @@ where } } +/// Like `std::io::Take`, but for lines instead of bytes. +/// +/// This struct is generally created by calling [`take_lines`] on a +/// reader. Please see the documentation of [`take`] for more +/// details. +pub struct TakeLines { + inner: T, + limit: usize, + separator: u8, +} + +impl Read for TakeLines { + /// Read bytes from a buffer up to the requested number of lines. + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + if self.limit == 0 { + return Ok(0); + } + match self.inner.read(buf) { + Ok(0) => Ok(0), + Ok(n) => { + for i in memchr_iter(self.separator, &buf[..n]) { + self.limit -= 1; + if self.limit == 0 { + return Ok(i + 1); + } + } + Ok(n) + } + Err(e) => Err(e), + } + } +} + +/// Create an adaptor that will read at most `limit` lines from a given reader. +/// +/// This function returns a new instance of `Read` that will read at +/// most `limit` lines, after which it will always return EOF +/// (`Ok(0)`). +/// +/// The `separator` defines the character to interpret as the line +/// ending. For the usual notion of "line", set this to `b'\n'`. +pub fn take_lines(reader: R, limit: usize, separator: u8) -> TakeLines { + TakeLines { + inner: reader, + limit, + separator, + } +} + #[cfg(test)] mod tests { + use std::io::BufRead; + use std::io::BufReader; + use crate::take::take_all_but; + use crate::take::take_lines; #[test] fn test_fewer_elements() { @@ -90,4 +147,33 @@ mod tests { assert_eq!(Some(&2), iter.next()); assert_eq!(None, iter.next()); } + + #[test] + fn test_zero_lines() { + let input_reader = std::io::Cursor::new("a\nb\nc\n"); + let output_reader = BufReader::new(take_lines(input_reader, 0, b'\n')); + let mut iter = output_reader.lines().map(|l| l.unwrap()); + assert_eq!(None, iter.next()); + } + + #[test] + fn test_fewer_lines() { + let input_reader = std::io::Cursor::new("a\nb\nc\n"); + let output_reader = BufReader::new(take_lines(input_reader, 2, b'\n')); + let mut iter = output_reader.lines().map(|l| l.unwrap()); + assert_eq!(Some(String::from("a")), iter.next()); + assert_eq!(Some(String::from("b")), iter.next()); + assert_eq!(None, iter.next()); + } + + #[test] + fn test_more_lines() { + let input_reader = std::io::Cursor::new("a\nb\nc\n"); + let output_reader = BufReader::new(take_lines(input_reader, 4, b'\n')); + let mut iter = output_reader.lines().map(|l| l.unwrap()); + assert_eq!(Some(String::from("a")), iter.next()); + assert_eq!(Some(String::from("b")), iter.next()); + assert_eq!(Some(String::from("c")), iter.next()); + assert_eq!(None, iter.next()); + } } diff --git a/src/uu/hostid/Cargo.toml b/src/uu/hostid/Cargo.toml index 45ced472f..c56649742 100644 --- a/src/uu/hostid/Cargo.toml +++ b/src/uu/hostid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_hostid" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "hostid ~ (uutils) display the numeric identifier of the current host" @@ -17,8 +17,8 @@ path = "src/hostid.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "hostid" diff --git a/src/uu/hostid/src/hostid.rs b/src/uu/hostid/src/hostid.rs index 4c9cafa35..309e15990 100644 --- a/src/uu/hostid/src/hostid.rs +++ b/src/uu/hostid/src/hostid.rs @@ -7,9 +7,6 @@ // spell-checker:ignore (ToDO) gethostid -#[macro_use] -extern crate uucore; - use clap::{crate_version, App}; use libc::c_long; use uucore::error::UResult; diff --git a/src/uu/hostname/Cargo.toml b/src/uu/hostname/Cargo.toml index afd402f24..daaeb48f7 100644 --- a/src/uu/hostname/Cargo.toml +++ b/src/uu/hostname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_hostname" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "hostname ~ (uutils) display or set the host name of the current host" @@ -18,8 +18,8 @@ path = "src/hostname.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" hostname = { version = "0.3", features = ["set"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["wide"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["wide"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } winapi = { version="0.3", features=["sysinfoapi", "winsock2"] } [[bin]] diff --git a/src/uu/hostname/src/hostname.rs b/src/uu/hostname/src/hostname.rs index 2de6627e8..9c8504027 100644 --- a/src/uu/hostname/src/hostname.rs +++ b/src/uu/hostname/src/hostname.rs @@ -7,9 +7,6 @@ // spell-checker:ignore (ToDO) MAKEWORD addrs hashset -#[macro_use] -extern crate uucore; - use std::collections::hash_set::HashSet; use std::net::ToSocketAddrs; use std::str; diff --git a/src/uu/id/Cargo.toml b/src/uu/id/Cargo.toml index b58c7fd78..0039cfc8e 100644 --- a/src/uu/id/Cargo.toml +++ b/src/uu/id/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_id" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "id ~ (uutils) display user and group information for USER" @@ -16,8 +16,8 @@ path = "src/id.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries", "process"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries", "process"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } selinux = { version="0.2.1", optional = true } [[bin]] diff --git a/src/uu/install/Cargo.toml b/src/uu/install/Cargo.toml index d930b2fbd..0ae11b3c4 100644 --- a/src/uu/install/Cargo.toml +++ b/src/uu/install/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_install" -version = "0.0.7" +version = "0.0.8" authors = [ "Ben Eills ", "uutils developers", @@ -22,8 +22,8 @@ clap = { version = "2.33", features = ["wrap_help"] } filetime = "0.2" file_diff = "1.0.0" libc = ">= 0.2" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["mode", "perms", "entries"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs", "mode", "perms", "entries"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [dev-dependencies] time = "0.1.40" diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index 1c09f7f34..a93add322 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -461,6 +461,8 @@ fn standard(mut paths: Vec, b: Behavior) -> UResult<()> { return Err(InstallError::CreateDirFailed(parent.to_path_buf(), e).into()); } + // Silent the warning as we want to the error message + #[allow(clippy::question_mark)] if mode::chmod(parent, b.mode()).is_err() { return Err(InstallError::ChmodFailed(parent.to_path_buf()).into()); } @@ -583,6 +585,8 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> { } } + // Silent the warning as we want to the error message + #[allow(clippy::question_mark)] if mode::chmod(to, b.mode()).is_err() { return Err(InstallError::ChmodFailed(to.to_path_buf()).into()); } diff --git a/src/uu/join/Cargo.toml b/src/uu/join/Cargo.toml index 7e5ced498..1c140f544 100644 --- a/src/uu/join/Cargo.toml +++ b/src/uu/join/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_join" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "join ~ (uutils) merge lines from inputs with matching join fields" @@ -16,8 +16,8 @@ path = "src/join.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "join" diff --git a/src/uu/kill/Cargo.toml b/src/uu/kill/Cargo.toml index 82a8a4fd0..452b0f407 100644 --- a/src/uu/kill/Cargo.toml +++ b/src/uu/kill/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_kill" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "kill ~ (uutils) send a signal to a process" @@ -17,8 +17,8 @@ path = "src/kill.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["signals"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["signals"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "kill" diff --git a/src/uu/link/Cargo.toml b/src/uu/link/Cargo.toml index d37ac6761..275d3b5cc 100644 --- a/src/uu/link/Cargo.toml +++ b/src/uu/link/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_link" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "link ~ (uutils) create a hard (file system) link to FILE" @@ -16,8 +16,8 @@ path = "src/link.rs" [dependencies] libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } clap = { version = "2.33", features = ["wrap_help"] } [[bin]] diff --git a/src/uu/ln/Cargo.toml b/src/uu/ln/Cargo.toml index 476e13771..ba2c8de96 100644 --- a/src/uu/ln/Cargo.toml +++ b/src/uu/ln/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_ln" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "ln ~ (uutils) create a (file system) link to TARGET" @@ -17,8 +17,8 @@ path = "src/ln.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "ln" diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index 3c5f9afab..ed19ff887 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_logname" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "logname ~ (uutils) display the login name of the current user" @@ -17,8 +17,8 @@ path = "src/logname.rs" [dependencies] libc = "0.2.42" clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "logname" diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index e907e8e02..b918f6501 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_ls" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "ls ~ (uutils) display directory contents" @@ -24,9 +24,10 @@ termsize = "0.1.6" globset = "0.4.6" lscolors = { version = "0.7.1", features = ["ansi_term"] } uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore", features = ["entries", "fs"] } -uucore_procs = { version=">=0.0.6", package = "uucore_procs", path = "../../uucore_procs" } +uucore_procs = { version=">=0.0.7", package = "uucore_procs", path = "../../uucore_procs" } once_cell = "1.7.2" atty = "0.2" +selinux = { version="0.2.1", optional = true } [target.'cfg(unix)'.dependencies] lazy_static = "1.4.0" @@ -35,6 +36,9 @@ lazy_static = "1.4.0" name = "ls" path = "src/main.rs" +[features] +feat_selinux = ["selinux"] + [package.metadata.cargo-udeps.ignore] # Necessary for "make all" normal = ["uucore_procs"] diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index c5c65334e..3fa3b4f8e 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -50,6 +50,11 @@ use unicode_width::UnicodeWidthStr; use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR}; use uucore::{fs::display_permissions, version_cmp::version_cmp}; +#[cfg(not(feature = "selinux"))] +static CONTEXT_HELP_TEXT: &str = "print any security context of each file (not enabled)"; +#[cfg(feature = "selinux")] +static CONTEXT_HELP_TEXT: &str = "print any security context of each file"; + fn usage() -> String { format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase()) } @@ -129,6 +134,7 @@ pub mod options { pub static FULL_TIME: &str = "full-time"; pub static HIDE: &str = "hide"; pub static IGNORE: &str = "ignore"; + pub static CONTEXT: &str = "context"; } const DEFAULT_TERM_WIDTH: u16 = 80; @@ -239,6 +245,8 @@ struct Config { quoting_style: QuotingStyle, indicator_style: IndicatorStyle, time_style: TimeStyle, + context: bool, + selinux_supported: bool, } // Fields that can be removed or added to the long format @@ -250,9 +258,18 @@ struct LongFormat { numeric_uid_gid: bool, } +struct PaddingCollection { + longest_link_count_len: usize, + longest_uname_len: usize, + longest_group_len: usize, + longest_context_len: usize, + longest_size_len: usize, +} + impl Config { #[allow(clippy::cognitive_complexity)] fn from(options: &clap::ArgMatches) -> UResult { + let context = options.is_present(options::CONTEXT); let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) { ( match format_ { @@ -596,6 +613,17 @@ impl Config { quoting_style, indicator_style, time_style, + context, + selinux_supported: { + #[cfg(feature = "selinux")] + { + selinux::kernel_support() != selinux::KernelSupport::Unsupported + } + #[cfg(not(feature = "selinux"))] + { + false + } + }, }) } } @@ -1157,6 +1185,12 @@ only ignore '.' and '..'.", .overrides_with(options::FULL_TIME) .help("like -l --time-style=full-iso"), ) + .arg( + Arg::with_name(options::CONTEXT) + .short("Z") + .long(options::CONTEXT) + .help(CONTEXT_HELP_TEXT), + ) // Positional arguments .arg( Arg::with_name(options::PATHS) @@ -1181,6 +1215,7 @@ struct PathData { // PathBuf that all above data corresponds to p_buf: PathBuf, must_dereference: bool, + security_context: String, } impl PathData { @@ -1224,12 +1259,19 @@ impl PathData { None => OnceCell::new(), }; + let security_context = if config.context { + get_security_context(config, &p_buf, must_dereference) + } else { + String::new() + }; + Self { md: OnceCell::new(), ft, display_name, p_buf, must_dereference, + security_context, } } @@ -1398,7 +1440,7 @@ fn get_metadata(entry: &Path, dereference: bool) -> std::io::Result { } fn display_dir_entry_size(entry: &PathData, config: &Config) -> (usize, usize, usize, usize) { - // TODO: Cache/memoize the display_* results so we don't have to recalculate them. + // TODO: Cache/memorize the display_* results so we don't have to recalculate them. if let Some(md) = entry.md() { ( display_symlink_count(md).len(), @@ -1411,31 +1453,40 @@ fn display_dir_entry_size(entry: &PathData, config: &Config) -> (usize, usize, u } } -fn pad_left(string: String, count: usize) -> String { +fn pad_left(string: &str, count: usize) -> String { format!("{:>width$}", string, width = count) } -fn pad_right(string: String, count: usize) -> String { +fn pad_right(string: &str, count: usize) -> String { format!("{:) { + // `-Z`, `--context`: + // Display the SELinux security context or '?' if none is found. When used with the `-l` + // option, print the security context to the left of the size column. + if config.format == Format::Long { let ( mut longest_link_count_len, mut longest_uname_len, mut longest_group_len, + mut longest_context_len, mut longest_size_len, - ) = (1, 1, 1, 1); + ) = (1, 1, 1, 1, 1); let mut total_size = 0; for item in items { + let context_len = item.security_context.len(); let (link_count_len, uname_len, group_len, size_len) = display_dir_entry_size(item, config); longest_link_count_len = link_count_len.max(longest_link_count_len); longest_size_len = size_len.max(longest_size_len); longest_uname_len = uname_len.max(longest_uname_len); longest_group_len = group_len.max(longest_group_len); + if config.context { + longest_context_len = context_len.max(longest_context_len); + } longest_size_len = size_len.max(longest_size_len); total_size += item.md().map_or(0, |md| get_block_size(md, config)); } @@ -1447,16 +1498,31 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter display_grid(names, config.width, Direction::TopToBottom, out), @@ -1581,15 +1647,13 @@ fn display_grid( /// longest_link_count_len: usize, /// longest_uname_len: usize, /// longest_group_len: usize, +/// longest_context_len: usize, /// longest_size_len: usize, /// ``` /// that decide the maximum possible character count of each field. fn display_item_long( item: &PathData, - longest_link_count_len: usize, - longest_uname_len: usize, - longest_group_len: usize, - longest_size_len: usize, + padding: PaddingCollection, config: &Config, out: &mut BufWriter, ) { @@ -1610,16 +1674,23 @@ fn display_item_long( let _ = write!( out, - "{} {}", + "{}{} {}", display_permissions(md, true), - pad_left(display_symlink_count(md), longest_link_count_len), + if item.security_context.len() > 1 { + // GNU `ls` uses a "." character to indicate a file with a security context, + // but not other alternate access method. + "." + } else { + "" + }, + pad_left(&display_symlink_count(md), padding.longest_link_count_len), ); if config.long.owner { let _ = write!( out, " {}", - pad_right(display_uname(md, config), longest_uname_len) + pad_right(&display_uname(md, config), padding.longest_uname_len) ); } @@ -1627,7 +1698,15 @@ fn display_item_long( let _ = write!( out, " {}", - pad_right(display_group(md, config), longest_group_len) + pad_right(&display_group(md, config), padding.longest_group_len) + ); + } + + if config.context { + let _ = write!( + out, + " {}", + pad_right(&item.security_context, padding.longest_context_len) ); } @@ -1637,19 +1716,19 @@ fn display_item_long( let _ = write!( out, " {}", - pad_right(display_uname(md, config), longest_uname_len) + pad_right(&display_uname(md, config), padding.longest_uname_len) ); } let _ = writeln!( out, " {} {} {}", - pad_left(display_size_or_rdev(md, config), longest_size_len), + pad_left(&display_size_or_rdev(md, config), padding.longest_size_len), display_date(md, config), // unwrap is fine because it fails when metadata is not available // but we already know that it is because it's checked at the // start of the function. - display_file_name(item, config).unwrap().contents, + display_file_name(item, config, None).unwrap().contents, ); } @@ -1873,21 +1952,22 @@ fn classify_file(path: &PathData) -> Option { /// * `config.indicator_style` to append specific characters to `name` using [`classify_file`]. /// * `config.format` to display symlink targets if `Format::Long`. This function is also /// responsible for coloring symlink target names if `config.color` is specified. +/// * `config.context` to prepend security context to `name` if compiled with `feat_selinux`. /// /// Note that non-unicode sequences in symlink targets are dealt with using /// [`std::path::Path::to_string_lossy`]. -fn display_file_name(path: &PathData, config: &Config) -> Option { +fn display_file_name( + path: &PathData, + config: &Config, + prefix_context: Option, +) -> Option { // This is our return value. We start by `&path.display_name` and modify it along the way. let mut name = escape_name(&path.display_name, &config.quoting_style); #[cfg(unix)] { if config.format != Format::Long && config.inode { - name = path - .md() - .map_or_else(|| "?".to_string(), |md| get_inode(md)) - + " " - + &name; + name = path.md().map_or_else(|| "?".to_string(), get_inode) + " " + &name; } } @@ -1968,6 +2048,20 @@ fn display_file_name(path: &PathData, config: &Config) -> Option { } } + // Prepend the security context to the `name` and adjust `width` in order + // to get correct alignment from later calls to`display_grid()`. + if config.context { + if let Some(pad_count) = prefix_context { + let security_context = if !matches!(config.format, Format::Commas) { + pad_left(&path.security_context, pad_count) + } else { + path.security_context.to_owned() + }; + name = format!("{} {}", security_context, name); + width += security_context.len() + 1; + } + } + Some(Cell { contents: name, width, @@ -1992,3 +2086,44 @@ fn display_symlink_count(_metadata: &Metadata) -> String { fn display_symlink_count(metadata: &Metadata) -> String { metadata.nlink().to_string() } + +// This returns the SELinux security context as UTF8 `String`. +// In the long term this should be changed to `OsStr`, see discussions at #2621/#2656 +#[allow(unused_variables)] +fn get_security_context(config: &Config, p_buf: &Path, must_dereference: bool) -> String { + let substitute_string = "?".to_string(); + if config.selinux_supported { + #[cfg(feature = "selinux")] + { + match selinux::SecurityContext::of_path(p_buf, must_dereference, false) { + Err(_r) => { + // TODO: show the actual reason why it failed + show_warning!("failed to get security context of: {}", p_buf.quote()); + substitute_string + } + Ok(None) => substitute_string, + Ok(Some(context)) => { + let mut context = context.as_bytes(); + if context.ends_with(&[0]) { + // TODO: replace with `strip_prefix()` when MSRV >= 1.51 + context = &context[..context.len() - 1] + }; + String::from_utf8(context.to_vec()).unwrap_or_else(|e| { + show_warning!( + "getting security context of: {}: {}", + p_buf.quote(), + e.to_string() + ); + String::from_utf8_lossy(context).into_owned() + }) + } + } + } + #[cfg(not(feature = "selinux"))] + { + substitute_string + } + } else { + substitute_string + } +} diff --git a/src/uu/mkdir/Cargo.toml b/src/uu/mkdir/Cargo.toml index 011d70af0..c0e6586ab 100644 --- a/src/uu/mkdir/Cargo.toml +++ b/src/uu/mkdir/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mkdir" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "mkdir ~ (uutils) create DIRECTORY" @@ -17,8 +17,8 @@ path = "src/mkdir.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs", "mode"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs", "mode"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "mkdir" diff --git a/src/uu/mkdir/src/mkdir.rs b/src/uu/mkdir/src/mkdir.rs index 92c068408..9ff816dcb 100644 --- a/src/uu/mkdir/src/mkdir.rs +++ b/src/uu/mkdir/src/mkdir.rs @@ -5,15 +5,22 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. +// spell-checker:ignore (ToDO) ugoa cmode + #[macro_use] extern crate uucore; use clap::OsValues; -use clap::{crate_version, App, Arg}; +use clap::{crate_version, App, Arg, ArgMatches}; use std::fs; use std::path::Path; use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError}; +#[cfg(not(windows))] +use uucore::mode; +use uucore::InvalidEncodingHandling; + +static DEFAULT_PERM: u32 = 0o755; static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist"; mod options { @@ -26,29 +33,81 @@ mod options { fn usage() -> String { format!("{0} [OPTION]... [USER]", uucore::execution_phrase()) } +fn get_long_usage() -> String { + String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.") +} + +#[cfg(windows)] +fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result { + Ok(DEFAULT_PERM) +} + +#[cfg(not(windows))] +fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result { + let digits: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + // Translate a ~str in octal form to u16, default to 755 + // Not tested on Windows + let mut new_mode = DEFAULT_PERM; + match matches.value_of(options::MODE) { + Some(m) => { + for mode in m.split(',') { + if mode.contains(digits) { + new_mode = mode::parse_numeric(new_mode, m, true)?; + } else { + let cmode = if mode_had_minus_prefix { + // clap parsing is finished, now put prefix back + format!("-{}", mode) + } else { + mode.to_string() + }; + new_mode = mode::parse_symbolic(new_mode, &cmode, mode::get_umask(), true)?; + } + } + Ok(new_mode) + } + None => Ok(DEFAULT_PERM), + } +} + +#[cfg(windows)] +fn strip_minus_from_mode(_args: &mut Vec) -> bool { + false +} + +#[cfg(not(windows))] +fn strip_minus_from_mode(args: &mut Vec) -> bool { + mode::strip_minus_from_mode(args) +} #[uucore_procs::gen_uumain] pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let mut args = args + .collect_str(InvalidEncodingHandling::ConvertLossy) + .accept_any(); + + // 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 usage = usage(); + 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().usage(&usage[..]).get_matches_from(args); + let matches = uu_app() + .usage(&usage[..]) + .after_help(&after_help[..]) + .get_matches_from(args); let dirs = matches.values_of_os(options::DIRS).unwrap_or_default(); let verbose = matches.is_present(options::VERBOSE); let recursive = matches.is_present(options::PARENTS); - // Translate a ~str in octal form to u16, default to 755 - // Not tested on Windows - let mode: u16 = match matches.value_of(options::MODE) { - Some(m) => u16::from_str_radix(m, 8) - .map_err(|_| USimpleError::new(1, format!("invalid mode {}", m.quote())))?, - None => 0o755_u16, - }; - - exec(dirs, recursive, mode, verbose) + match get_mode(&matches, mode_had_minus_prefix) { + Ok(mode) => exec(dirs, recursive, mode, verbose), + Err(f) => Err(USimpleError::new(1, f)), + } } pub fn uu_app() -> App<'static, 'static> { @@ -86,7 +145,7 @@ pub fn uu_app() -> App<'static, 'static> { /** * Create the list of new directories */ -fn exec(dirs: OsValues, recursive: bool, mode: u16, verbose: bool) -> UResult<()> { +fn exec(dirs: OsValues, recursive: bool, mode: u32, verbose: bool) -> UResult<()> { for dir in dirs { let path = Path::new(dir); show_if_err!(mkdir(path, recursive, mode, verbose)); @@ -94,7 +153,7 @@ fn exec(dirs: OsValues, recursive: bool, mode: u16, verbose: bool) -> UResult<() Ok(()) } -fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> UResult<()> { +fn mkdir(path: &Path, recursive: bool, mode: u32, verbose: bool) -> UResult<()> { let create_dir = if recursive { fs::create_dir_all } else { @@ -115,18 +174,18 @@ fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> UResult<()> } #[cfg(any(unix, target_os = "redox"))] -fn chmod(path: &Path, mode: u16) -> UResult<()> { +fn chmod(path: &Path, mode: u32) -> UResult<()> { use std::fs::{set_permissions, Permissions}; use std::os::unix::fs::PermissionsExt; - let mode = Permissions::from_mode(u32::from(mode)); + let mode = Permissions::from_mode(mode); set_permissions(path, mode) .map_err_context(|| format!("cannot set permissions {}", path.quote())) } #[cfg(windows)] -fn chmod(_path: &Path, _mode: u16) -> UResult<()> { +fn chmod(_path: &Path, _mode: u32) -> UResult<()> { // chmod on Windows only sets the readonly flag, which isn't even honored on directories Ok(()) } diff --git a/src/uu/mkfifo/Cargo.toml b/src/uu/mkfifo/Cargo.toml index 01d6bad64..acf38f6bc 100644 --- a/src/uu/mkfifo/Cargo.toml +++ b/src/uu/mkfifo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mkfifo" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "mkfifo ~ (uutils) create FIFOs (named pipes)" @@ -17,8 +17,8 @@ path = "src/mkfifo.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "mkfifo" diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index e6073d50c..046e4b8d0 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mknod" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "mknod ~ (uutils) create special file NAME of TYPE" @@ -18,8 +18,8 @@ path = "src/mknod.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "^0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["mode"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["mode"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "mknod" diff --git a/src/uu/mktemp/Cargo.toml b/src/uu/mktemp/Cargo.toml index 4c9a8d29c..de896dba7 100644 --- a/src/uu/mktemp/Cargo.toml +++ b/src/uu/mktemp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mktemp" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "mktemp ~ (uutils) create and display a temporary file or directory from TEMPLATE" @@ -18,8 +18,8 @@ path = "src/mktemp.rs" clap = { version = "2.33", features = ["wrap_help"] } rand = "0.5" tempfile = "3.1" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "mktemp" diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 81a3521e9..4318f0ad6 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -8,9 +8,6 @@ // spell-checker:ignore (paths) GPGHome -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use uucore::display::{println_verbatim, Quotable}; use uucore::error::{FromIo, UError, UResult}; diff --git a/src/uu/more/Cargo.toml b/src/uu/more/Cargo.toml index cd292eea9..0111376f9 100644 --- a/src/uu/more/Cargo.toml +++ b/src/uu/more/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_more" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "more ~ (uutils) input perusal filter" @@ -17,7 +17,7 @@ path = "src/more.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } uucore = { version = ">=0.0.7", package = "uucore", path = "../../uucore" } -uucore_procs = { version=">=0.0.6", package = "uucore_procs", path = "../../uucore_procs" } +uucore_procs = { version=">=0.0.7", package = "uucore_procs", path = "../../uucore_procs" } crossterm = ">=0.19" atty = "0.2" unicode-width = "0.1.7" diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index 3a601c1e8..d424d5a77 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -210,7 +210,7 @@ fn reset_term(stdout: &mut std::io::Stdout) { #[inline(always)] fn reset_term(_: &mut usize) {} -fn more(buff: &str, mut stdout: &mut Stdout, next_file: Option<&str>, silent: bool) { +fn more(buff: &str, stdout: &mut Stdout, next_file: Option<&str>, silent: bool) { let (cols, rows) = terminal::size().unwrap(); let lines = break_buff(buff, usize::from(cols)); @@ -232,7 +232,7 @@ fn more(buff: &str, mut stdout: &mut Stdout, next_file: Option<&str>, silent: bo code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, }) => { - reset_term(&mut stdout); + reset_term(stdout); std::process::exit(0); } Event::Key(KeyEvent { diff --git a/src/uu/mv/Cargo.toml b/src/uu/mv/Cargo.toml index 82b1da6e1..6dd129af9 100644 --- a/src/uu/mv/Cargo.toml +++ b/src/uu/mv/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mv" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "mv ~ (uutils) move (rename) SOURCE to DESTINATION" @@ -17,8 +17,8 @@ path = "src/mv.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } fs_extra = "1.1.0" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "mv" diff --git a/src/uu/nice/Cargo.toml b/src/uu/nice/Cargo.toml index 5f0c2c07a..ac719a768 100644 --- a/src/uu/nice/Cargo.toml +++ b/src/uu/nice/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nice" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "nice ~ (uutils) run PROGRAM with modified scheduling priority" @@ -18,8 +18,8 @@ path = "src/nice.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" nix = "0.20" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "nice" diff --git a/src/uu/nl/Cargo.toml b/src/uu/nl/Cargo.toml index ca0d7827d..781f6502d 100644 --- a/src/uu/nl/Cargo.toml +++ b/src/uu/nl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nl" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "nl ~ (uutils) display input with added line numbers" @@ -21,8 +21,8 @@ libc = "0.2.42" memchr = "2.2.0" regex = "1.0.1" regex-syntax = "0.6.7" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "nl" diff --git a/src/uu/nohup/Cargo.toml b/src/uu/nohup/Cargo.toml index d7de60b0b..c2f3c329e 100644 --- a/src/uu/nohup/Cargo.toml +++ b/src/uu/nohup/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nohup" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "nohup ~ (uutils) run COMMAND, ignoring hangup signals" @@ -18,8 +18,8 @@ path = "src/nohup.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" atty = "0.2" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "nohup" diff --git a/src/uu/nproc/Cargo.toml b/src/uu/nproc/Cargo.toml index e02bec7e1..3c44062bd 100644 --- a/src/uu/nproc/Cargo.toml +++ b/src/uu/nproc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nproc" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "nproc ~ (uutils) display the number of processing units available" @@ -18,8 +18,8 @@ path = "src/nproc.rs" libc = "0.2.42" num_cpus = "1.10" clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "nproc" diff --git a/src/uu/numfmt/Cargo.toml b/src/uu/numfmt/Cargo.toml index 6239da7f9..60bfb3b14 100644 --- a/src/uu/numfmt/Cargo.toml +++ b/src/uu/numfmt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_numfmt" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "numfmt ~ (uutils) reformat NUMBER" @@ -16,8 +16,8 @@ path = "src/numfmt.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "numfmt" diff --git a/src/uu/od/Cargo.toml b/src/uu/od/Cargo.toml index ee785e773..a6b5bc433 100644 --- a/src/uu/od/Cargo.toml +++ b/src/uu/od/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_od" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "od ~ (uutils) display formatted representation of input" @@ -19,8 +19,8 @@ byteorder = "1.3.2" clap = { version = "2.33", features = ["wrap_help"] } half = "1.6" libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "od" diff --git a/src/uu/od/src/output_info.rs b/src/uu/od/src/output_info.rs index 49c2a09a2..cf050475a 100644 --- a/src/uu/od/src/output_info.rs +++ b/src/uu/od/src/output_info.rs @@ -145,13 +145,12 @@ impl OutputInfo { byte_size_block: usize, print_width_block: usize, ) -> [usize; MAX_BYTES_PER_UNIT] { - if byte_size_block > MAX_BYTES_PER_UNIT { - panic!( - "{}-bits types are unsupported. Current max={}-bits.", - 8 * byte_size_block, - 8 * MAX_BYTES_PER_UNIT - ); - } + assert!( + byte_size_block <= MAX_BYTES_PER_UNIT, + "{}-bits types are unsupported. Current max={}-bits.", + 8 * byte_size_block, + 8 * MAX_BYTES_PER_UNIT + ); let mut spacing = [0; MAX_BYTES_PER_UNIT]; let mut byte_size = sf.byte_size(); diff --git a/src/uu/paste/Cargo.toml b/src/uu/paste/Cargo.toml index c4873b1d0..aeba6f68e 100644 --- a/src/uu/paste/Cargo.toml +++ b/src/uu/paste/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_paste" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "paste ~ (uutils) merge lines from inputs" @@ -16,8 +16,8 @@ path = "src/paste.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "paste" diff --git a/src/uu/pathchk/Cargo.toml b/src/uu/pathchk/Cargo.toml index d7e76728a..79e0c251b 100644 --- a/src/uu/pathchk/Cargo.toml +++ b/src/uu/pathchk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pathchk" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "pathchk ~ (uutils) diagnose invalid or non-portable PATHNAME" @@ -17,8 +17,8 @@ path = "src/pathchk.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "pathchk" diff --git a/src/uu/pinky/Cargo.toml b/src/uu/pinky/Cargo.toml index a84aa7473..297d40642 100644 --- a/src/uu/pinky/Cargo.toml +++ b/src/uu/pinky/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pinky" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "pinky ~ (uutils) display user information" @@ -15,8 +15,8 @@ edition = "2018" path = "src/pinky.rs" [dependencies] -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["utmpx", "entries"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["utmpx", "entries"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } clap = { version = "2.33", features = ["wrap_help"] } [[bin]] diff --git a/src/uu/pr/Cargo.toml b/src/uu/pr/Cargo.toml index 09993c3b9..499ee7726 100644 --- a/src/uu/pr/Cargo.toml +++ b/src/uu/pr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pr" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "pr ~ (uutils) convert text files for printing" @@ -17,7 +17,7 @@ path = "src/pr.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } getopts = "0.2.21" chrono = "0.4.19" quick-error = "2.0.1" diff --git a/src/uu/pr/src/pr.rs b/src/uu/pr/src/pr.rs index 45d9480a7..0886a9991 100644 --- a/src/uu/pr/src/pr.rs +++ b/src/uu/pr/src/pr.rs @@ -20,7 +20,7 @@ use quick_error::ResultExt; use regex::Regex; use std::convert::From; use std::fs::{metadata, File}; -use std::io::{stdin, stdout, BufRead, BufReader, Lines, Read, Stdout, Write}; +use std::io::{stdin, stdout, BufRead, BufReader, Lines, Read, Write}; #[cfg(unix)] use std::os::unix::fs::FileTypeExt; @@ -1036,15 +1036,16 @@ fn print_page(lines: &[FileLine], options: &OutputOptions, page: usize) -> Resul let header = header_content(options, page); let trailer_content = trailer_content(options); - let out = &mut stdout(); - out.lock(); + let out = stdout(); + let mut out = out.lock(); + for x in header { out.write_all(x.as_bytes())?; out.write_all(line_separator)?; } - let lines_written = write_columns(lines, options, out)?; + let lines_written = write_columns(lines, options, &mut out)?; for (index, x) in trailer_content.iter().enumerate() { out.write_all(x.as_bytes())?; @@ -1060,7 +1061,7 @@ fn print_page(lines: &[FileLine], options: &OutputOptions, page: usize) -> Resul fn write_columns( lines: &[FileLine], options: &OutputOptions, - out: &mut Stdout, + out: &mut impl Write, ) -> Result { let line_separator = options.content_line_separator.as_bytes(); diff --git a/src/uu/printenv/Cargo.toml b/src/uu/printenv/Cargo.toml index 466f69af0..eaf482b21 100644 --- a/src/uu/printenv/Cargo.toml +++ b/src/uu/printenv/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_printenv" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "printenv ~ (uutils) display value of environment VAR" @@ -16,8 +16,8 @@ path = "src/printenv.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "printenv" diff --git a/src/uu/printf/Cargo.toml b/src/uu/printf/Cargo.toml index f4034083a..50c454db5 100644 --- a/src/uu/printf/Cargo.toml +++ b/src/uu/printf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_printf" -version = "0.0.7" +version = "0.0.8" authors = [ "Nathan Ross", "uutils developers", @@ -20,8 +20,8 @@ path = "src/printf.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } itertools = "0.8.0" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "printf" diff --git a/src/uu/ptx/Cargo.toml b/src/uu/ptx/Cargo.toml index fea4e5c1f..06eb15ee8 100644 --- a/src/uu/ptx/Cargo.toml +++ b/src/uu/ptx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_ptx" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "ptx ~ (uutils) display a permuted index of input" @@ -21,8 +21,8 @@ libc = "0.2.42" memchr = "2.2.0" regex = "1.0.1" regex-syntax = "0.6.7" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "ptx" diff --git a/src/uu/pwd/Cargo.toml b/src/uu/pwd/Cargo.toml index 37cbc7fe6..a168fb5aa 100644 --- a/src/uu/pwd/Cargo.toml +++ b/src/uu/pwd/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pwd" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "pwd ~ (uutils) display current working directory" @@ -16,8 +16,8 @@ path = "src/pwd.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "pwd" diff --git a/src/uu/pwd/src/pwd.rs b/src/uu/pwd/src/pwd.rs index 1138dba8e..8beb65dbd 100644 --- a/src/uu/pwd/src/pwd.rs +++ b/src/uu/pwd/src/pwd.rs @@ -5,9 +5,6 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use std::env; use std::io; diff --git a/src/uu/readlink/Cargo.toml b/src/uu/readlink/Cargo.toml index 8552f611d..d126a3835 100644 --- a/src/uu/readlink/Cargo.toml +++ b/src/uu/readlink/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_readlink" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "readlink ~ (uutils) display resolved path of PATHNAME" @@ -17,8 +17,8 @@ path = "src/readlink.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "readlink" diff --git a/src/uu/realpath/Cargo.toml b/src/uu/realpath/Cargo.toml index 3916c4ce6..4be39f978 100644 --- a/src/uu/realpath/Cargo.toml +++ b/src/uu/realpath/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_realpath" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "realpath ~ (uutils) display resolved absolute path of PATHNAME" @@ -16,8 +16,8 @@ path = "src/realpath.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "realpath" diff --git a/src/uu/relpath/Cargo.toml b/src/uu/relpath/Cargo.toml index bcb048af9..f1ddf87dc 100644 --- a/src/uu/relpath/Cargo.toml +++ b/src/uu/relpath/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_relpath" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "relpath ~ (uutils) display relative path of PATHNAME_TO from PATHNAME_FROM" @@ -16,8 +16,8 @@ path = "src/relpath.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "relpath" diff --git a/src/uu/rm/Cargo.toml b/src/uu/rm/Cargo.toml index 6099d137a..757fa8b22 100644 --- a/src/uu/rm/Cargo.toml +++ b/src/uu/rm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_rm" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "rm ~ (uutils) remove PATHNAME" @@ -18,8 +18,8 @@ path = "src/rm.rs" clap = { version = "2.33", features = ["wrap_help"] } walkdir = "2.2" remove_dir_all = "0.5.1" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(windows)'.dependencies] winapi = { version="0.3", features=[] } diff --git a/src/uu/rmdir/Cargo.toml b/src/uu/rmdir/Cargo.toml index cdb08f908..bc05773a8 100644 --- a/src/uu/rmdir/Cargo.toml +++ b/src/uu/rmdir/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_rmdir" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "rmdir ~ (uutils) remove empty DIRECTORY" @@ -16,8 +16,8 @@ path = "src/rmdir.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } libc = "0.2.42" [[bin]] diff --git a/src/uu/runcon/Cargo.toml b/src/uu/runcon/Cargo.toml index 4e4c0bed6..ff06e72a1 100644 --- a/src/uu/runcon/Cargo.toml +++ b/src/uu/runcon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_runcon" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "runcon ~ (uutils) run command with specified security context" diff --git a/src/uu/seq/Cargo.toml b/src/uu/seq/Cargo.toml index 4618115cb..f5a23310f 100644 --- a/src/uu/seq/Cargo.toml +++ b/src/uu/seq/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_seq" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "seq ~ (uutils) display a sequence of numbers" @@ -18,8 +18,8 @@ path = "src/seq.rs" clap = { version = "2.33", features = ["wrap_help"] } num-bigint = "0.4.0" num-traits = "0.2.14" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "seq" diff --git a/src/uu/seq/src/seq.rs b/src/uu/seq/src/seq.rs index aac8f2280..a76a23c4e 100644 --- a/src/uu/seq/src/seq.rs +++ b/src/uu/seq/src/seq.rs @@ -88,30 +88,65 @@ impl FromStr for Number { if s.starts_with('+') { s = &s[1..]; } + let is_neg = s.starts_with('-'); - match s.parse::() { - Ok(n) => { - // If `s` is '-0', then `parse()` returns - // `BigInt::zero()`, but we need to return - // `Number::MinusZero` instead. - if n == BigInt::zero() && s.starts_with('-') { - Ok(Number::MinusZero) - } else { - Ok(Number::BigInt(n)) + match s.to_lowercase().find("0x") { + Some(i) if i <= 1 => match &s.as_bytes()[i + 2] { + b'-' | b'+' => Err(format!( + "invalid hexadecimal argument: {}\nTry '{} --help' for more information.", + s.quote(), + uucore::execution_phrase(), + )), + // TODO: hexadecimal floating point parsing (see #2660) + b'.' => Err(format!( + "NotImplemented: hexadecimal floating point numbers: {}\nTry '{} --help' for more information.", + s.quote(), + uucore::execution_phrase(), + )), + _ => { + let num = BigInt::from_str_radix(&s[i + 2..], 16) + .map_err(|_| format!( + "invalid hexadecimal argument: {}\nTry '{} --help' for more information.", + s.quote(), + uucore::execution_phrase(), + ))?; + match (is_neg, num == BigInt::zero()) { + (true, true) => Ok(Number::MinusZero), + (true, false) => Ok(Number::BigInt(-num)), + (false, _) => Ok(Number::BigInt(num)), + } + } + }, + Some(_) => Err(format!( + "invalid hexadecimal argument: {}\nTry '{} --help' for more information.", + s.quote(), + uucore::execution_phrase(), + )), + + None => match s.parse::() { + Ok(n) => { + // If `s` is '-0', then `parse()` returns + // `BigInt::zero()`, but we need to return + // `Number::MinusZero` instead. + if n == BigInt::zero() && is_neg { + Ok(Number::MinusZero) + } else { + Ok(Number::BigInt(n)) + } } - } - Err(_) => match s.parse::() { - Ok(value) if value.is_nan() => Err(format!( + Err(_) => match s.parse::() { + Ok(value) if value.is_nan() => Err(format!( "invalid 'not-a-number' argument: {}\nTry '{} --help' for more information.", s.quote(), uucore::execution_phrase(), )), - Ok(value) => Ok(Number::F64(value)), - Err(_) => Err(format!( + Ok(value) => Ok(Number::F64(value)), + Err(_) => Err(format!( "invalid floating point argument: {}\nTry '{} --help' for more information.", s.quote(), uucore::execution_phrase(), )), + }, }, } } diff --git a/src/uu/shred/Cargo.toml b/src/uu/shred/Cargo.toml index d87732d84..00356d701 100644 --- a/src/uu/shred/Cargo.toml +++ b/src/uu/shred/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_shred" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "shred ~ (uutils) hide former FILE contents with repeated overwrites" @@ -18,8 +18,8 @@ path = "src/shred.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" rand = "0.7" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "shred" diff --git a/src/uu/shuf/Cargo.toml b/src/uu/shuf/Cargo.toml index bb3ccc710..35da41145 100644 --- a/src/uu/shuf/Cargo.toml +++ b/src/uu/shuf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_shuf" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "shuf ~ (uutils) display random permutations of input lines" @@ -17,8 +17,8 @@ path = "src/shuf.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } rand = "0.5" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "shuf" diff --git a/src/uu/sleep/Cargo.toml b/src/uu/sleep/Cargo.toml index 8414f444c..af6f22b9f 100644 --- a/src/uu/sleep/Cargo.toml +++ b/src/uu/sleep/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sleep" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "sleep ~ (uutils) pause for DURATION" @@ -16,8 +16,8 @@ path = "src/sleep.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "sleep" diff --git a/src/uu/sleep/src/sleep.rs b/src/uu/sleep/src/sleep.rs index a70a524c4..80e8cd852 100644 --- a/src/uu/sleep/src/sleep.rs +++ b/src/uu/sleep/src/sleep.rs @@ -5,9 +5,6 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use std::thread; use std::time::Duration; diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index 7faf9906e..b3d4fe0ea 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sort" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "sort ~ (uutils) sort input lines" @@ -27,8 +27,8 @@ rand = "0.7" rayon = "1.5" tempfile = "3" unicode-width = "0.1.8" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "sort" diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index fe286aa6d..ae1bcfa4c 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -171,10 +171,6 @@ impl UError for SortError { _ => 2, } } - - fn usage(&self) -> bool { - false - } } impl Display for SortError { @@ -663,18 +659,14 @@ impl<'a> Line<'a> { " ".repeat(UnicodeWidthStr::width(&line[..selection.start])) )?; - // TODO: Once our minimum supported rust version is at least 1.47, use selection.is_empty() instead. - #[allow(clippy::len_zero)] - { - if selection.len() == 0 { - writeln!(writer, "^ no match for key")?; - } else { - writeln!( - writer, - "{}", - "_".repeat(UnicodeWidthStr::width(&line[selection])) - )?; - } + if selection.is_empty() { + writeln!(writer, "^ no match for key")?; + } else { + writeln!( + writer, + "{}", + "_".repeat(UnicodeWidthStr::width(&line[selection])) + )?; } } if settings.mode != SortMode::Random @@ -825,7 +817,7 @@ impl FieldSelector { fn parse(key: &str, global_settings: &GlobalSettings) -> UResult { let mut from_to = key.split(','); let (from, from_options) = Self::split_key_options(from_to.next().unwrap()); - let to = from_to.next().map(|to| Self::split_key_options(to)); + let to = from_to.next().map(Self::split_key_options); let options_are_empty = from_options.is_empty() && matches!(to, None | Some((_, ""))); if options_are_empty { diff --git a/src/uu/split/Cargo.toml b/src/uu/split/Cargo.toml index d2168bf49..44d0350b2 100644 --- a/src/uu/split/Cargo.toml +++ b/src/uu/split/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_split" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "split ~ (uutils) split input into output files" @@ -16,8 +16,8 @@ path = "src/split.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "split" diff --git a/src/uu/stat/Cargo.toml b/src/uu/stat/Cargo.toml index dec209ea0..a1f168b14 100644 --- a/src/uu/stat/Cargo.toml +++ b/src/uu/stat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_stat" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "stat ~ (uutils) display FILE status" @@ -16,8 +16,8 @@ path = "src/stat.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries", "libc", "fs", "fsext"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries", "libc", "fs", "fsext"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "stat" diff --git a/src/uu/stdbuf/Cargo.toml b/src/uu/stdbuf/Cargo.toml index e9e162803..45863cd0c 100644 --- a/src/uu/stdbuf/Cargo.toml +++ b/src/uu/stdbuf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_stdbuf" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "stdbuf ~ (uutils) run COMMAND with modified standard stream buffering" @@ -17,11 +17,11 @@ path = "src/stdbuf.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } tempfile = "3.1" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [build-dependencies] -libstdbuf = { version="0.0.7", package="uu_stdbuf_libstdbuf", path="src/libstdbuf" } +libstdbuf = { version="0.0.8", package="uu_stdbuf_libstdbuf", path="src/libstdbuf" } [[bin]] name = "stdbuf" diff --git a/src/uu/stdbuf/src/libstdbuf/Cargo.toml b/src/uu/stdbuf/src/libstdbuf/Cargo.toml index 9f86fcd17..069a2ae11 100644 --- a/src/uu/stdbuf/src/libstdbuf/Cargo.toml +++ b/src/uu/stdbuf/src/libstdbuf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_stdbuf_libstdbuf" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "stdbuf/libstdbuf ~ (uutils); dynamic library required for stdbuf" @@ -19,8 +19,8 @@ crate-type = ["cdylib", "rlib"] # XXX: note: the rlib is just to prevent Cargo f [dependencies] cpp = "0.5" libc = "0.2" -uucore = { version=">=0.0.9", package="uucore", path="../../../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../../../uucore_procs" } [build-dependencies] cpp_build = "0.4" diff --git a/src/uu/sum/Cargo.toml b/src/uu/sum/Cargo.toml index 41f2d0a38..273f9dff9 100644 --- a/src/uu/sum/Cargo.toml +++ b/src/uu/sum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sum" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "sum ~ (uutils) display checksum and block counts for input" @@ -16,8 +16,8 @@ path = "src/sum.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "sum" diff --git a/src/uu/sum/src/sum.rs b/src/uu/sum/src/sum.rs index 15c20f09d..c58a1dcdc 100644 --- a/src/uu/sum/src/sum.rs +++ b/src/uu/sum/src/sum.rs @@ -76,6 +76,8 @@ fn open(name: &str) -> Result> { "Is a directory", )); }; + // Silent the warning as we want to the error message + #[allow(clippy::question_mark)] if path.metadata().is_err() { return Err(std::io::Error::new( std::io::ErrorKind::NotFound, diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index a745ac6f8..4bf2c60b3 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sync" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "sync ~ (uutils) synchronize cache writes to storage" @@ -17,8 +17,8 @@ path = "src/sync.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["wide"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["wide"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } winapi = { version = "0.3", features = ["errhandlingapi", "fileapi", "handleapi", "std", "winbase", "winerror"] } [[bin]] diff --git a/src/uu/tac/BENCHMARKING.md b/src/uu/tac/BENCHMARKING.md new file mode 100644 index 000000000..4e6d13ea2 --- /dev/null +++ b/src/uu/tac/BENCHMARKING.md @@ -0,0 +1,25 @@ +## Benchmarking `tac` + + + +`tac` is often used to process log files in reverse chronological order, i.e. from newer towards older entries. In this case, the performance target to yield results as fast as possible, i.e. without reading in the whole file that is to be reversed line-by-line. Therefore, a sensible benchmark is to read a large log file containing N lines and measure how long it takes to produce the last K lines from that file. + +Large text files can for example be found in the [Wikipedia database dumps](https://dumps.wikimedia.org/wikidatawiki/latest/), usually sized at multiple gigabytes and comprising more than 100M lines. + +After you have obtained and uncompressed such a file, you need to build `tac` in release mode + +```shell +$ cargo build --release --package uu_tac +``` + +and then you can time how it long it takes to extract the last 10M lines by running + +```shell +$ /usr/bin/time ./target/release/tac wikidatawiki-20211001-pages-logging.xml | head -n10000000 >/dev/null +``` + +For more systematic measurements that include warm-ups, repetitions and comparisons, [Hyperfine](https://github.com/sharkdp/hyperfine) can be helpful. For example, to compare this implementation to the one provided by your distribution run + +```shell +$ hyperfine "./target/release/tac wikidatawiki-20211001-pages-logging.xml | head -n10000000 >/dev/null" "/usr/bin/tac wikidatawiki-20211001-pages-logging.xml | head -n10000000 >/dev/null" +``` diff --git a/src/uu/tac/Cargo.toml b/src/uu/tac/Cargo.toml index 1e436e916..6840d6bc3 100644 --- a/src/uu/tac/Cargo.toml +++ b/src/uu/tac/Cargo.toml @@ -1,6 +1,8 @@ +# spell-checker:ignore memmap + [package] name = "uu_tac" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "tac ~ (uutils) concatenate and display input lines in reverse order" @@ -16,10 +18,11 @@ path = "src/tac.rs" [dependencies] memchr = "2" +memmap2 = "0.5" regex = "1" clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "tac" diff --git a/src/uu/tac/src/tac.rs b/src/uu/tac/src/tac.rs index 4a93a7c65..cdb2d74e3 100644 --- a/src/uu/tac/src/tac.rs +++ b/src/uu/tac/src/tac.rs @@ -5,15 +5,19 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -// spell-checker:ignore (ToDO) sbytes slen dlen memmem +// spell-checker:ignore (ToDO) sbytes slen dlen memmem memmap Mmap mmap SIGBUS #[macro_use] extern crate uucore; use clap::{crate_version, App, Arg}; use memchr::memmem; -use std::io::{stdin, stdout, BufReader, Read, Write}; -use std::{fs::File, path::Path}; +use memmap2::Mmap; +use std::io::{stdin, stdout, BufWriter, Read, Write}; +use std::{ + fs::{read, File}, + path::Path, +}; use uucore::display::Quotable; use uucore::InvalidEncodingHandling; @@ -44,9 +48,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 { raw_separator }; - let files: Vec = match matches.values_of(options::FILE) { - Some(v) => v.map(|v| v.to_owned()).collect(), - None => vec!["-".to_owned()], + let files: Vec<&str> = match matches.values_of(options::FILE) { + Some(v) => v.collect(), + None => vec!["-"], }; tac(files, before, regex, separator) @@ -102,10 +106,11 @@ pub fn uu_app() -> App<'static, 'static> { /// returns [`std::io::Error`]. fn buffer_tac_regex( data: &[u8], - pattern: regex::bytes::Regex, + pattern: ®ex::bytes::Regex, before: bool, ) -> std::io::Result<()> { - let mut out = stdout(); + let out = stdout(); + let mut out = BufWriter::new(out.lock()); // The index of the line separator for the current line. // @@ -171,7 +176,8 @@ fn buffer_tac_regex( /// `separator` appears at the beginning of each line, as in /// `"/abc/def"`. fn buffer_tac(data: &[u8], before: bool, separator: &str) -> std::io::Result<()> { - let mut out = stdout(); + let out = stdout(); + let mut out = BufWriter::new(out.lock()); // The number of bytes in the line separator. let slen = separator.as_bytes().len(); @@ -208,12 +214,33 @@ fn buffer_tac(data: &[u8], before: bool, separator: &str) -> std::io::Result<()> Ok(()) } -fn tac(filenames: Vec, before: bool, regex: bool, separator: &str) -> i32 { +fn tac(filenames: Vec<&str>, before: bool, regex: bool, separator: &str) -> i32 { let mut exit_code = 0; - for filename in &filenames { - let mut file = BufReader::new(if filename == "-" { - Box::new(stdin()) as Box + let pattern = if regex { + Some(crash_if_err!(1, regex::bytes::Regex::new(separator))) + } else { + None + }; + + for &filename in &filenames { + let mmap; + let buf; + + let data: &[u8] = if filename == "-" { + if let Some(mmap1) = try_mmap_stdin() { + mmap = mmap1; + &mmap + } else { + let mut buf1 = Vec::new(); + if let Err(e) = stdin().read_to_end(&mut buf1) { + show_error!("failed to read from stdin: {}", e); + exit_code = 1; + continue; + } + buf = buf1; + &buf + } } else { let path = Path::new(filename); if path.is_dir() || path.metadata().is_err() { @@ -228,29 +255,47 @@ fn tac(filenames: Vec, before: bool, regex: bool, separator: &str) -> i3 exit_code = 1; continue; } - match File::open(path) { - Ok(f) => Box::new(f) as Box, - Err(e) => { - show_error!("failed to open {} for reading: {}", filename.quote(), e); - exit_code = 1; - continue; + + if let Some(mmap1) = try_mmap_path(path) { + mmap = mmap1; + &mmap + } else { + match read(path) { + Ok(buf1) => { + buf = buf1; + &buf + } + Err(e) => { + show_error!("failed to read {}: {}", filename.quote(), e); + exit_code = 1; + continue; + } } } - }); - - let mut data = Vec::new(); - if let Err(e) = file.read_to_end(&mut data) { - show_error!("failed to read {}: {}", filename.quote(), e); - exit_code = 1; - continue; }; - if regex { - let pattern = crash_if_err!(1, regex::bytes::Regex::new(separator)); - buffer_tac_regex(&data, pattern, before) + + if let Some(pattern) = &pattern { + buffer_tac_regex(data, pattern, before) } else { - buffer_tac(&data, before, separator) + buffer_tac(data, before, separator) } .unwrap_or_else(|e| crash!(1, "failed to write to stdout: {}", e)); } exit_code } + +fn try_mmap_stdin() -> Option { + // SAFETY: If the file is truncated while we map it, SIGBUS will be raised + // and our process will be terminated, thus preventing access of invalid memory. + unsafe { Mmap::map(&stdin()).ok() } +} + +fn try_mmap_path(path: &Path) -> Option { + let file = File::open(path).ok()?; + + // SAFETY: If the file is truncated while we map it, SIGBUS will be raised + // and our process will be terminated, thus preventing access of invalid memory. + let mmap = unsafe { Mmap::map(&file).ok()? }; + + Some(mmap) +} diff --git a/src/uu/tail/Cargo.toml b/src/uu/tail/Cargo.toml index 47578c78e..8289290c2 100644 --- a/src/uu/tail/Cargo.toml +++ b/src/uu/tail/Cargo.toml @@ -1,7 +1,7 @@ # spell-checker:ignore (libs) kqueue [package] name = "uu_tail" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "tail ~ (uutils) display the last lines of input" @@ -19,8 +19,8 @@ path = "src/tail.rs" clap = { version = "2.33", features = ["wrap_help"] } notify = { version = "5.0.0-pre.13", features=["macos_kqueue"]} libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["ringbuffer"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["ringbuffer"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(windows)'.dependencies] winapi = { version="0.3", features=["fileapi", "handleapi", "processthreadsapi", "synchapi", "winbase"] } diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs index 88bb3da9f..4aeb3858c 100644 --- a/src/uu/tail/src/tail.rs +++ b/src/uu/tail/src/tail.rs @@ -46,6 +46,15 @@ use crate::platform::stdin_is_pipe_or_fifo; #[cfg(unix)] use std::os::unix::fs::MetadataExt; +const ABOUT: &str = "\ + Print the last 10 lines of each FILE to standard output.\n\ + With more than one FILE, precede each with a header giving the file name.\n\ + With no FILE, or when FILE is -, read standard input.\n\ + \n\ + Mandatory arguments to long flags are mandatory for short flags too.\ + "; +const USAGE: &str = "tail [FLAG]... [FILE]..."; + pub mod text { pub static STDIN_STR: &str = "standard input"; pub static NO_FILES_REMAINING: &str = "no files remaining"; @@ -370,8 +379,8 @@ pub fn uu_app() -> App<'static, 'static> { App::new(uucore::util_name()) .version(crate_version!()) - .about("output the last part of files") - // TODO: add usage + .about(ABOUT) + .usage(USAGE) .arg( Arg::with_name(options::BYTES) .short("c") diff --git a/src/uu/tee/Cargo.toml b/src/uu/tee/Cargo.toml index 900ef3564..00a250565 100644 --- a/src/uu/tee/Cargo.toml +++ b/src/uu/tee/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tee" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "tee ~ (uutils) display input and copy to FILE" @@ -18,8 +18,8 @@ path = "src/tee.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" retain_mut = "0.1.2" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["libc"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["libc"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "tee" diff --git a/src/uu/test/Cargo.toml b/src/uu/test/Cargo.toml index 3fe531d1d..633e0f323 100644 --- a/src/uu/test/Cargo.toml +++ b/src/uu/test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_test" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "test ~ (uutils) evaluate comparison and file type expressions" @@ -17,8 +17,8 @@ path = "src/test.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(target_os = "redox")'.dependencies] redox_syscall = "0.2" diff --git a/src/uu/timeout/Cargo.toml b/src/uu/timeout/Cargo.toml index 3e17669e0..13afe8435 100644 --- a/src/uu/timeout/Cargo.toml +++ b/src/uu/timeout/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_timeout" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "timeout ~ (uutils) run COMMAND with a DURATION time limit" @@ -18,8 +18,8 @@ path = "src/timeout.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" nix = "0.20.0" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["process", "signals"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["process", "signals"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] diff --git a/src/uu/touch/Cargo.toml b/src/uu/touch/Cargo.toml index 5bb5822ec..b21e2dfa3 100644 --- a/src/uu/touch/Cargo.toml +++ b/src/uu/touch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_touch" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "touch ~ (uutils) change FILE timestamps" @@ -18,8 +18,8 @@ path = "src/touch.rs" filetime = "0.2.1" clap = { version = "2.33", features = ["wrap_help"] } time = "0.1.40" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["libc"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["libc"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "touch" diff --git a/src/uu/tr/Cargo.toml b/src/uu/tr/Cargo.toml index 450c562e0..8792938a9 100644 --- a/src/uu/tr/Cargo.toml +++ b/src/uu/tr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tr" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "tr ~ (uutils) translate characters within input and display" @@ -18,8 +18,8 @@ path = "src/tr.rs" bit-set = "0.5.0" fnv = "1.0.5" clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "tr" diff --git a/src/uu/true/Cargo.toml b/src/uu/true/Cargo.toml index 36ea0f991..369bbb51f 100644 --- a/src/uu/true/Cargo.toml +++ b/src/uu/true/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_true" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "true ~ (uutils) do nothing and succeed" @@ -16,8 +16,8 @@ path = "src/true.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "true" diff --git a/src/uu/true/src/true.rs b/src/uu/true/src/true.rs index 6b4a87bf1..b5fbf7c9d 100644 --- a/src/uu/true/src/true.rs +++ b/src/uu/true/src/true.rs @@ -5,9 +5,6 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use clap::App; use uucore::error::UResult; diff --git a/src/uu/truncate/Cargo.toml b/src/uu/truncate/Cargo.toml index e779e32ba..811aa6ef6 100644 --- a/src/uu/truncate/Cargo.toml +++ b/src/uu/truncate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_truncate" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "truncate ~ (uutils) truncate (or extend) FILE to SIZE" @@ -16,8 +16,8 @@ path = "src/truncate.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "truncate" diff --git a/src/uu/tsort/Cargo.toml b/src/uu/tsort/Cargo.toml index 055615003..bcc2dd757 100644 --- a/src/uu/tsort/Cargo.toml +++ b/src/uu/tsort/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tsort" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "tsort ~ (uutils) topologically sort input (partially ordered) pairs" @@ -16,8 +16,8 @@ path = "src/tsort.rs" [dependencies] clap= "2.33" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "tsort" diff --git a/src/uu/tty/Cargo.toml b/src/uu/tty/Cargo.toml index 6a4cb73a6..5b2e18cd2 100644 --- a/src/uu/tty/Cargo.toml +++ b/src/uu/tty/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tty" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "tty ~ (uutils) display the name of the terminal connected to standard input" @@ -18,8 +18,8 @@ path = "src/tty.rs" clap = { version = "2.33", features = ["wrap_help"] } libc = "0.2.42" atty = "0.2" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["fs"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "tty" diff --git a/src/uu/uname/Cargo.toml b/src/uu/uname/Cargo.toml index a12b095aa..90a103075 100644 --- a/src/uu/uname/Cargo.toml +++ b/src/uu/uname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_uname" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "uname ~ (uutils) display system information" @@ -17,8 +17,8 @@ path = "src/uname.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } platform-info = "0.1" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "uname" diff --git a/src/uu/unexpand/Cargo.toml b/src/uu/unexpand/Cargo.toml index 8b1169151..026a12872 100644 --- a/src/uu/unexpand/Cargo.toml +++ b/src/uu/unexpand/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_unexpand" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "unexpand ~ (uutils) convert input spaces to tabs" @@ -17,8 +17,8 @@ path = "src/unexpand.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } unicode-width = "0.1.5" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "unexpand" diff --git a/src/uu/uniq/Cargo.toml b/src/uu/uniq/Cargo.toml index 06ba22688..a6fcebc92 100644 --- a/src/uu/uniq/Cargo.toml +++ b/src/uu/uniq/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_uniq" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "uniq ~ (uutils) filter identical adjacent lines from input" @@ -18,8 +18,8 @@ path = "src/uniq.rs" clap = { version = "2.33", features = ["wrap_help"] } strum = "0.21" strum_macros = "0.21" -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "uniq" diff --git a/src/uu/uniq/src/uniq.rs b/src/uu/uniq/src/uniq.rs index f84bfc26d..c6c6a444d 100644 --- a/src/uu/uniq/src/uniq.rs +++ b/src/uu/uniq/src/uniq.rs @@ -5,16 +5,14 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg, ArgMatches}; use std::fs::File; -use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Result, Write}; +use std::io::{self, stdin, stdout, BufRead, BufReader, BufWriter, Read, Write}; use std::path::Path; use std::str::FromStr; use strum_macros::{AsRefStr, EnumString}; use uucore::display::Quotable; +use uucore::error::{FromIo, UResult, USimpleError}; static ABOUT: &str = "Report or omit repeated lines."; pub mod options { @@ -55,36 +53,45 @@ struct Uniq { zero_terminated: bool, } +macro_rules! write_line_terminator { + ($writer:expr, $line_terminator:expr) => { + $writer + .write_all(&[$line_terminator]) + .map_err_context(|| "Could not write line terminator".to_string()) + }; +} + impl Uniq { pub fn print_uniq( &self, reader: &mut BufReader, writer: &mut BufWriter, - ) { + ) -> UResult<()> { let mut first_line_printed = false; let mut group_count = 1; let line_terminator = self.get_line_terminator(); let mut lines = reader.split(line_terminator).map(get_line_string); let mut line = match lines.next() { - Some(l) => l, - None => return, + Some(l) => l?, + None => return Ok(()), }; // compare current `line` with consecutive lines (`next_line`) of the input // and if needed, print `line` based on the command line options provided for next_line in lines { + let next_line = next_line?; if self.cmp_keys(&line, &next_line) { if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) { - self.print_line(writer, &line, group_count, first_line_printed); + self.print_line(writer, &line, group_count, first_line_printed)?; first_line_printed = true; } line = next_line; group_count = 1; } else { if self.all_repeated { - self.print_line(writer, &line, group_count, first_line_printed); + self.print_line(writer, &line, group_count, first_line_printed)?; first_line_printed = true; line = next_line; } @@ -92,14 +99,15 @@ impl Uniq { } } if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) { - self.print_line(writer, &line, group_count, first_line_printed); + self.print_line(writer, &line, group_count, first_line_printed)?; first_line_printed = true; } if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both) && first_line_printed { - crash_if_err!(1, writer.write_all(&[line_terminator])); + write_line_terminator!(writer, line_terminator)?; } + Ok(()) } fn skip_fields<'a>(&self, line: &'a str) -> &'a str { @@ -191,41 +199,43 @@ impl Uniq { line: &str, count: usize, first_line_printed: bool, - ) { + ) -> UResult<()> { let line_terminator = self.get_line_terminator(); if self.should_print_delimiter(count, first_line_printed) { - crash_if_err!(1, writer.write_all(&[line_terminator])); + write_line_terminator!(writer, line_terminator)?; } - crash_if_err!( - 1, - if self.show_counts { - writer.write_all(format!("{:7} {}", count, line).as_bytes()) - } else { - writer.write_all(line.as_bytes()) - } - ); - crash_if_err!(1, writer.write_all(&[line_terminator])); + if self.show_counts { + writer.write_all(format!("{:7} {}", count, line).as_bytes()) + } else { + writer.write_all(line.as_bytes()) + } + .map_err_context(|| "Failed to write line".to_string())?; + + write_line_terminator!(writer, line_terminator) } } -fn get_line_string(io_line: Result>) -> String { - let line_bytes = crash_if_err!(1, io_line); - crash_if_err!(1, String::from_utf8(line_bytes)) +fn get_line_string(io_line: io::Result>) -> UResult { + let line_bytes = io_line.map_err_context(|| "failed to split lines".to_string())?; + String::from_utf8(line_bytes) + .map_err(|e| USimpleError::new(1, format!("failed to convert line to utf8: {}", e))) } -fn opt_parsed(opt_name: &str, matches: &ArgMatches) -> Option { - matches.value_of(opt_name).map(|arg_str| { - let opt_val: Option = arg_str.parse().ok(); - opt_val.unwrap_or_else(|| { - crash!( +fn opt_parsed(opt_name: &str, matches: &ArgMatches) -> UResult> { + Ok(match matches.value_of(opt_name) { + Some(arg_str) => Some(arg_str.parse().map_err(|_| { + USimpleError::new( 1, - "Invalid argument for {}: {}", - opt_name, - arg_str.maybe_quote() + format!( + "Invalid argument for {}: {}", + opt_name, + arg_str.maybe_quote() + ), ) - }) + })?), + None => None, }) } @@ -245,7 +255,8 @@ fn get_long_usage() -> String { ) } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let usage = usage(); let long_usage = get_long_usage(); @@ -264,8 +275,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { 1 => (files[0].clone(), "-".to_owned()), 2 => (files[0].clone(), files[1].clone()), _ => { - // Cannot happen as clap will fail earlier - crash!(1, "Extra operand: {}", files[2]); + unreachable!() // Cannot happen as clap will fail earlier } }; @@ -277,18 +287,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 { || matches.is_present(options::GROUP), delimiters: get_delimiter(&matches), show_counts: matches.is_present(options::COUNT), - skip_fields: opt_parsed(options::SKIP_FIELDS, &matches), - slice_start: opt_parsed(options::SKIP_CHARS, &matches), - slice_stop: opt_parsed(options::CHECK_CHARS, &matches), + skip_fields: opt_parsed(options::SKIP_FIELDS, &matches)?, + slice_start: opt_parsed(options::SKIP_CHARS, &matches)?, + slice_stop: opt_parsed(options::CHECK_CHARS, &matches)?, ignore_case: matches.is_present(options::IGNORE_CASE), zero_terminated: matches.is_present(options::ZERO_TERMINATED), }; uniq.print_uniq( - &mut open_input_file(in_file_name), - &mut open_output_file(out_file_name), - ); - - 0 + &mut open_input_file(in_file_name)?, + &mut open_output_file(out_file_name)?, + ) } pub fn uu_app() -> App<'static, 'static> { @@ -388,7 +396,7 @@ fn get_delimiter(matches: &ArgMatches) -> Delimiters { .value_of(options::ALL_REPEATED) .or_else(|| matches.value_of(options::GROUP)); if let Some(delimiter_arg) = value { - crash_if_err!(1, Delimiters::from_str(delimiter_arg)) + Delimiters::from_str(delimiter_arg).unwrap() // All possible values for ALL_REPEATED are &str's of Delimiters } else if matches.is_present(options::GROUP) { Delimiters::Separate } else { @@ -396,26 +404,26 @@ fn get_delimiter(matches: &ArgMatches) -> Delimiters { } } -fn open_input_file(in_file_name: String) -> BufReader> { +fn open_input_file(in_file_name: String) -> UResult>> { let in_file = if in_file_name == "-" { Box::new(stdin()) as Box } else { let path = Path::new(&in_file_name[..]); - let in_file = File::open(&path); - let r = crash_if_err!(1, in_file); - Box::new(r) as Box + let in_file = File::open(&path) + .map_err_context(|| format!("Could not open {}", in_file_name.maybe_quote()))?; + Box::new(in_file) as Box }; - BufReader::new(in_file) + Ok(BufReader::new(in_file)) } -fn open_output_file(out_file_name: String) -> BufWriter> { +fn open_output_file(out_file_name: String) -> UResult>> { let out_file = if out_file_name == "-" { Box::new(stdout()) as Box } else { let path = Path::new(&out_file_name[..]); - let in_file = File::create(&path); - let w = crash_if_err!(1, in_file); - Box::new(w) as Box + let out_file = File::create(&path) + .map_err_context(|| format!("Could not create {}", out_file_name.maybe_quote()))?; + Box::new(out_file) as Box }; - BufWriter::new(out_file) + Ok(BufWriter::new(out_file)) } diff --git a/src/uu/unlink/Cargo.toml b/src/uu/unlink/Cargo.toml index 558d18422..c4b7d49cb 100644 --- a/src/uu/unlink/Cargo.toml +++ b/src/uu/unlink/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_unlink" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "unlink ~ (uutils) remove a (file system) link to FILE" @@ -16,8 +16,8 @@ path = "src/unlink.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore" } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore" } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "unlink" diff --git a/src/uu/unlink/src/unlink.rs b/src/uu/unlink/src/unlink.rs index 1b4e4c998..58bb5442c 100644 --- a/src/uu/unlink/src/unlink.rs +++ b/src/uu/unlink/src/unlink.rs @@ -7,9 +7,6 @@ /* last synced with: unlink (GNU coreutils) 8.21 */ -#[macro_use] -extern crate uucore; - use std::fs::remove_file; use std::path::Path; diff --git a/src/uu/uptime/Cargo.toml b/src/uu/uptime/Cargo.toml index a5b7a3177..785955afc 100644 --- a/src/uu/uptime/Cargo.toml +++ b/src/uu/uptime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_uptime" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "uptime ~ (uutils) display dynamic system information" @@ -17,8 +17,8 @@ path = "src/uptime.rs" [dependencies] chrono = "0.4" clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["libc", "utmpx"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["libc", "utmpx"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "uptime" diff --git a/src/uu/uptime/src/uptime.rs b/src/uu/uptime/src/uptime.rs index f649b96b6..eabcd1abf 100644 --- a/src/uu/uptime/src/uptime.rs +++ b/src/uu/uptime/src/uptime.rs @@ -11,8 +11,6 @@ use chrono::{Local, TimeZone, Utc}; use clap::{crate_version, App, Arg}; -#[macro_use] -extern crate uucore; // import crate time from utmpx pub use uucore::libc; use uucore::libc::time_t; diff --git a/src/uu/users/Cargo.toml b/src/uu/users/Cargo.toml index ec4f0785e..05872e8bf 100644 --- a/src/uu/users/Cargo.toml +++ b/src/uu/users/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_users" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "users ~ (uutils) display names of currently logged-in users" @@ -16,8 +16,8 @@ path = "src/users.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["utmpx"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["utmpx"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [[bin]] name = "users" diff --git a/src/uu/users/src/users.rs b/src/uu/users/src/users.rs index d374df181..d0768d8d1 100644 --- a/src/uu/users/src/users.rs +++ b/src/uu/users/src/users.rs @@ -11,6 +11,7 @@ use std::path::Path; use clap::{crate_version, App, Arg}; +use uucore::error::UResult; use uucore::utmpx::{self, Utmpx}; static ABOUT: &str = "Print the user names of users currently logged in to the current host"; @@ -29,7 +30,8 @@ If FILE is not specified, use {}. /var/log/wtmp as FILE is common.", ) } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let usage = usage(); let after_help = get_long_usage(); @@ -59,7 +61,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { println!("{}", users.join(" ")); } - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> { diff --git a/src/uu/wc/Cargo.toml b/src/uu/wc/Cargo.toml index 179b17c36..d76e0b176 100644 --- a/src/uu/wc/Cargo.toml +++ b/src/uu/wc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_wc" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "wc ~ (uutils) display newline, word, and byte counts for input" @@ -16,8 +16,8 @@ path = "src/wc.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["pipes"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["pipes"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } bytecount = "0.6.2" utf-8 = "0.7.6" unicode-width = "0.1.8" diff --git a/src/uu/wc/src/count_fast.rs b/src/uu/wc/src/count_fast.rs index 9351b6871..e4f6be6c1 100644 --- a/src/uu/wc/src/count_fast.rs +++ b/src/uu/wc/src/count_fast.rs @@ -50,6 +50,8 @@ fn count_bytes_using_splice(fd: &impl AsRawFd) -> Result { Ok(0) => break, Ok(res) => { byte_count += res; + // Silent the warning as we want to the error message + #[allow(clippy::question_mark)] if splice_exact(&pipe_rd, &null_file, res).is_err() { return Err(byte_count); } diff --git a/src/uu/who/Cargo.toml b/src/uu/who/Cargo.toml index 1b3abe91e..c660be59d 100644 --- a/src/uu/who/Cargo.toml +++ b/src/uu/who/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_who" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "who ~ (uutils) display information about currently logged-in users" @@ -15,8 +15,8 @@ edition = "2018" path = "src/who.rs" [dependencies] -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["utmpx"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["utmpx"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } clap = { version = "2.33", features = ["wrap_help"] } [[bin]] diff --git a/src/uu/whoami/Cargo.toml b/src/uu/whoami/Cargo.toml index d12ea1aea..5af93579f 100644 --- a/src/uu/whoami/Cargo.toml +++ b/src/uu/whoami/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_whoami" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "whoami ~ (uutils) display user name of current effective user ID" @@ -16,8 +16,8 @@ path = "src/whoami.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["entries"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["lmcons"] } diff --git a/src/uu/whoami/src/whoami.rs b/src/uu/whoami/src/whoami.rs index 830b86e63..0820588ee 100644 --- a/src/uu/whoami/src/whoami.rs +++ b/src/uu/whoami/src/whoami.rs @@ -9,8 +9,6 @@ #[macro_use] extern crate clap; -#[macro_use] -extern crate uucore; use clap::App; diff --git a/src/uu/yes/Cargo.toml b/src/uu/yes/Cargo.toml index ea2aae3b1..ad8a87b46 100644 --- a/src/uu/yes/Cargo.toml +++ b/src/uu/yes/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_yes" -version = "0.0.7" +version = "0.0.8" authors = ["uutils developers"] license = "MIT" description = "yes ~ (uutils) repeatedly display a line with STRING (or 'y')" @@ -16,8 +16,8 @@ path = "src/yes.rs" [dependencies] clap = { version = "2.33", features = ["wrap_help"] } -uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["pipes"] } -uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" } +uucore = { version=">=0.0.10", package="uucore", path="../../uucore", features=["pipes"] } +uucore_procs = { version=">=0.0.7", package="uucore_procs", path="../../uucore_procs" } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] nix = "0.20.0" diff --git a/src/uu/yes/src/yes.rs b/src/uu/yes/src/yes.rs index 03ae4e415..bbedc0af1 100644 --- a/src/uu/yes/src/yes.rs +++ b/src/uu/yes/src/yes.rs @@ -12,8 +12,6 @@ use std::io::{self, Write}; #[macro_use] extern crate clap; -#[macro_use] -extern crate uucore; use clap::{App, Arg}; use uucore::error::{UResult, USimpleError}; diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 3f2276bd3..952eecc28 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uucore" -version = "0.0.9" +version = "0.0.10" authors = ["uutils developers"] license = "MIT" description = "uutils ~ 'core' uutils code library (cross-platform)" diff --git a/src/uucore/src/lib/features/mode.rs b/src/uucore/src/lib/features/mode.rs index 72083e799..5e299f988 100644 --- a/src/uucore/src/lib/features/mode.rs +++ b/src/uucore/src/lib/features/mode.rs @@ -155,6 +155,30 @@ pub fn get_umask() -> u32 { mask as u32 } +// Iterate 'args' and delete the first occurrence +// of a prefix '-' if it's associated with MODE +// e.g. "chmod -v -xw -R FILE" -> "chmod -v xw -R FILE" +pub fn strip_minus_from_mode(args: &mut Vec) -> bool { + for arg in args { + if arg == "--" { + break; + } + if arg.starts_with('-') { + if let Some(second) = arg.chars().nth(1) { + match second { + 'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => { + // TODO: use strip_prefix() once minimum rust version reaches 1.45.0 + *arg = arg[1..arg.len()].to_string(); + return true; + } + _ => {} + } + } + } + } + false +} + #[cfg(test)] mod test { diff --git a/src/uucore_procs/Cargo.toml b/src/uucore_procs/Cargo.toml index 809bbc867..3efe80e00 100644 --- a/src/uucore_procs/Cargo.toml +++ b/src/uucore_procs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uucore_procs" -version = "0.0.6" +version = "0.0.7" authors = ["Roy Ivy III "] license = "MIT" description = "uutils ~ 'uucore' proc-macros" diff --git a/src/uucore_procs/src/lib.rs b/src/uucore_procs/src/lib.rs index 092a4a66c..13b1dae3b 100644 --- a/src/uucore_procs/src/lib.rs +++ b/src/uucore_procs/src/lib.rs @@ -101,7 +101,7 @@ pub fn gen_uumain(_args: TokenStream, stream: TokenStream) -> TokenStream { Err(e) => { let s = format!("{}", e); if s != "" { - show_error!("{}", s); + uucore::show_error!("{}", s); } if e.usage() { eprintln!("Try '{} --help' for more information.", uucore::execution_phrase()); diff --git a/tests/by-util/test_base32.rs b/tests/by-util/test_base32.rs index 5c74c5b59..ffe2cf74c 100644 --- a/tests/by-util/test_base32.rs +++ b/tests/by-util/test_base32.rs @@ -113,12 +113,18 @@ fn test_wrap_bad_arg() { #[test] fn test_base32_extra_operand() { + let ts = TestScenario::new(util_name!()); + // Expect a failure when multiple files are specified. - new_ucmd!() + ts.ucmd() .arg("a.txt") .arg("b.txt") .fails() - .stderr_only("base32: extra operand 'b.txt'\nTry 'base32 --help' for more information."); + .stderr_only(format!( + "{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.", + ts.util_name, + ts.bin_path.to_string_lossy() + )); } #[test] diff --git a/tests/by-util/test_base64.rs b/tests/by-util/test_base64.rs index a860aae91..87aa0db44 100644 --- a/tests/by-util/test_base64.rs +++ b/tests/by-util/test_base64.rs @@ -95,12 +95,18 @@ fn test_wrap_bad_arg() { #[test] fn test_base64_extra_operand() { + let ts = TestScenario::new(util_name!()); + // Expect a failure when multiple files are specified. - new_ucmd!() + ts.ucmd() .arg("a.txt") .arg("b.txt") .fails() - .stderr_only("base64: extra operand 'b.txt'\nTry 'base64 --help' for more information."); + .stderr_only(format!( + "{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.", + ts.util_name, + ts.bin_path.to_string_lossy() + )); } #[test] diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index 1b8983bc3..c8348d491 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -4,7 +4,7 @@ use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; use std::sync::Mutex; extern crate libc; -use self::chmod::strip_minus_from_mode; +use uucore::mode::strip_minus_from_mode; extern crate chmod; use self::libc::umask; diff --git a/tests/by-util/test_chroot.rs b/tests/by-util/test_chroot.rs index 65d821d01..3e5c22679 100644 --- a/tests/by-util/test_chroot.rs +++ b/tests/by-util/test_chroot.rs @@ -15,6 +15,7 @@ fn test_missing_operand() { #[test] fn test_enter_chroot_fails() { + // NOTE: since #2689 this test also ensures that we don't regress #2687 let (at, mut ucmd) = at_and_ucmd!(); at.mkdir("jail"); @@ -89,3 +90,26 @@ fn test_preference_of_userspec() { println!("result.stdout = {}", result.stdout_str()); println!("result.stderr = {}", result.stderr_str()); } + +#[test] +fn test_default_shell() { + // NOTE: This test intends to trigger code which can only be reached with root permissions. + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + let dir = "CHROOT_DIR"; + at.mkdir(dir); + + let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string()); + let _expected = format!( + "chroot: failed to run command '{}': No such file or directory", + shell + ); + + // TODO: [2021-09; jhscheer] uncomment if/when #2692 gets merged + // if let Ok(result) = run_ucmd_as_root(&ts, &[dir]) { + // result.stderr_contains(expected); + // } else { + // print!("TEST SKIPPED"); + // } +} diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 918be21f3..8340c7059 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -28,9 +28,7 @@ macro_rules! fixture_path { macro_rules! assert_fixture_exists { ($fname:expr) => {{ let fpath = fixture_path!($fname); - if !fpath.exists() { - panic!("Fixture missing: {:?}", fpath); - } + assert!(fpath.exists(), "Fixture missing: {:?}", fpath); }}; } @@ -38,9 +36,7 @@ macro_rules! assert_fixture_exists { macro_rules! assert_fixture_not_exists { ($fname:expr) => {{ let fpath = PathBuf::from(format!("./fixtures/dd/{}", $fname)); - if fpath.exists() { - panic!("Fixture present: {:?}", fpath); - } + assert!(!fpath.exists(), "Fixture present: {:?}", fpath); }}; } diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 4082a5015..56711d6e0 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -347,6 +347,7 @@ fn test_ls_long_format() { // A line of the output should be: // One of the characters -bcCdDlMnpPsStTx? // rwx, with - for missing permissions, thrice. + // Zero or one "." for indicating a file with security context // A number, preceded by column whitespace, and followed by a single space. // A username, currently [^ ], followed by column whitespace, twice (or thrice for Hurd). // A number, followed by a single space. @@ -356,13 +357,13 @@ fn test_ls_long_format() { // and followed by a single space. // Whatever comes after is irrelevant to this specific test. scene.ucmd().arg(arg).arg("test-long-dir").succeeds().stdout_matches(&Regex::new( - r"\n[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} +\d+ [^ ]+ +[^ ]+( +[^ ]+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ " + r"\n[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3}\.? +\d+ [^ ]+ +[^ ]+( +[^ ]+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ " ).unwrap()); } // This checks for the line with the .. entry. The uname and group should be digits. scene.ucmd().arg("-lan").arg("test-long-dir").succeeds().stdout_matches(&Regex::new( - r"\nd([r-][w-][xt-]){3} +\d+ \d+ +\d+( +\d+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ \.\." + r"\nd([r-][w-][xt-]){3}\.? +\d+ \d+ +\d+( +\d+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ \.\." ).unwrap()); } @@ -370,6 +371,7 @@ fn test_ls_long_format() { /// This test is mainly about coloring, but, the recursion, symlink `->` processing, /// and `.` and `..` being present in `-a` all need to work for the test to pass. /// This test does not really test anything provided by `-l` but the file names and symlinks. +#[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))] #[test] #[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))] fn test_ls_long_symlink_color() { @@ -636,55 +638,57 @@ fn test_ls_long_formats() { let at = &scene.fixtures; at.touch(&at.plus_as_string("test-long-formats")); + // Zero or one "." for indicating a file with security context + // Regex for three names, so all of author, group and owner - let re_three = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){3}0").unwrap(); + let re_three = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){3}0").unwrap(); #[cfg(unix)] - let re_three_num = Regex::new(r"[xrw-]{9} \d (\d+ ){3}0").unwrap(); + let re_three_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){3}0").unwrap(); // Regex for two names, either: // - group and owner // - author and owner // - author and group - let re_two = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){2}0").unwrap(); + let re_two = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){2}0").unwrap(); #[cfg(unix)] - let re_two_num = Regex::new(r"[xrw-]{9} \d (\d+ ){2}0").unwrap(); + let re_two_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){2}0").unwrap(); // Regex for one name: author, group or owner - let re_one = Regex::new(r"[xrw-]{9} \d [-0-9_a-z]+ 0").unwrap(); + let re_one = Regex::new(r"[xrw-]{9}\.? \d [-0-9_a-z]+ 0").unwrap(); #[cfg(unix)] - let re_one_num = Regex::new(r"[xrw-]{9} \d \d+ 0").unwrap(); + let re_one_num = Regex::new(r"[xrw-]{9}\.? \d \d+ 0").unwrap(); // Regex for no names - let re_zero = Regex::new(r"[xrw-]{9} \d 0").unwrap(); + let re_zero = Regex::new(r"[xrw-]{9}\.? \d 0").unwrap(); - let result = scene + scene .ucmd() .arg("-l") .arg("--author") .arg("test-long-formats") - .succeeds(); - assert!(re_three.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_three); - let result = scene + scene .ucmd() .arg("-l1") .arg("--author") .arg("test-long-formats") - .succeeds(); - assert!(re_three.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_three); #[cfg(unix)] { - let result = scene + scene .ucmd() .arg("-n") .arg("--author") .arg("test-long-formats") - .succeeds(); - assert!(re_three_num.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_three_num); } for arg in &[ @@ -694,22 +698,22 @@ fn test_ls_long_formats() { "-lG --author", // only author and owner "-l --no-group --author", // only author and owner ] { - let result = scene + scene .ucmd() .args(&arg.split(' ').collect::>()) .arg("test-long-formats") - .succeeds(); - assert!(re_two.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_two); #[cfg(unix)] { - let result = scene + scene .ucmd() .arg("-n") .args(&arg.split(' ').collect::>()) .arg("test-long-formats") - .succeeds(); - assert!(re_two_num.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_two_num); } } @@ -723,22 +727,22 @@ fn test_ls_long_formats() { "-l --no-group", // only owner "-gG --author", // only author ] { - let result = scene + scene .ucmd() .args(&arg.split(' ').collect::>()) .arg("test-long-formats") - .succeeds(); - assert!(re_one.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_one); #[cfg(unix)] { - let result = scene + scene .ucmd() .arg("-n") .args(&arg.split(' ').collect::>()) .arg("test-long-formats") - .succeeds(); - assert!(re_one_num.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_one_num); } } @@ -755,22 +759,22 @@ fn test_ls_long_formats() { "-og1", "-og1l", ] { - let result = scene + scene .ucmd() .args(&arg.split(' ').collect::>()) .arg("test-long-formats") - .succeeds(); - assert!(re_zero.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_zero); #[cfg(unix)] { - let result = scene + scene .ucmd() .arg("-n") .args(&arg.split(' ').collect::>()) .arg("test-long-formats") - .succeeds(); - assert!(re_zero.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_zero); } } } @@ -1248,7 +1252,7 @@ fn test_ls_inode() { at.touch(file); let re_short = Regex::new(r" *(\d+) test_inode").unwrap(); - let re_long = Regex::new(r" *(\d+) [xrw-]{10} \d .+ test_inode").unwrap(); + let re_long = Regex::new(r" *(\d+) [xrw-]{10}\.? \d .+ test_inode").unwrap(); let result = scene.ucmd().arg("test_inode").arg("-i").succeeds(); assert!(re_short.is_match(result.stdout_str())); @@ -2272,3 +2276,68 @@ fn test_ls_dangling_symlinks() { .succeeds() // this should fail, though at the moment, ls lacks a way to propagate errors encountered during display .stdout_contains(if cfg!(windows) { "dangle" } else { "? dangle" }); } + +#[test] +#[cfg(feature = "feat_selinux")] +fn test_ls_context1() { + use selinux::{self, KernelSupport}; + if selinux::kernel_support() == KernelSupport::Unsupported { + println!("test skipped: Kernel has no support for SElinux context",); + return; + } + + let file = "test_ls_context_file"; + let expected = format!("unconfined_u:object_r:user_tmp_t:s0 {}\n", file); + let (at, mut ucmd) = at_and_ucmd!(); + at.touch(file); + ucmd.args(&["-Z", file]).succeeds().stdout_is(expected); +} + +#[test] +#[cfg(feature = "feat_selinux")] +fn test_ls_context2() { + use selinux::{self, KernelSupport}; + if selinux::kernel_support() == KernelSupport::Unsupported { + println!("test skipped: Kernel has no support for SElinux context",); + return; + } + let ts = TestScenario::new(util_name!()); + for c_flag in &["-Z", "--context"] { + ts.ucmd() + .args(&[c_flag, &"/"]) + .succeeds() + .stdout_only(unwrap_or_return!(expected_result(&ts, &[c_flag, &"/"])).stdout_str()); + } +} + +#[test] +#[cfg(feature = "feat_selinux")] +fn test_ls_context_format() { + use selinux::{self, KernelSupport}; + if selinux::kernel_support() == KernelSupport::Unsupported { + println!("test skipped: Kernel has no support for SElinux context",); + return; + } + let ts = TestScenario::new(util_name!()); + // NOTE: + // --format=long/verbose matches the output of GNU's ls for --context + // except for the size count which may differ to the size count reported by GNU's ls. + for word in &[ + "across", + "commas", + "horizontal", + // "long", + "single-column", + // "verbose", + "vertical", + ] { + let format = format!("--format={}", word); + ts.ucmd() + .args(&[&"-Z", &format.as_str(), &"/"]) + .succeeds() + .stdout_only( + unwrap_or_return!(expected_result(&ts, &[&"-Z", &format.as_str(), &"/"])) + .stdout_str(), + ); + } +} diff --git a/tests/by-util/test_mkdir.rs b/tests/by-util/test_mkdir.rs index 54a6fe3c8..f3451fb5e 100644 --- a/tests/by-util/test_mkdir.rs +++ b/tests/by-util/test_mkdir.rs @@ -1,4 +1,6 @@ use crate::common::util::*; +#[cfg(not(windows))] +use std::os::unix::fs::PermissionsExt; static TEST_DIR1: &str = "mkdir_test1"; static TEST_DIR2: &str = "mkdir_test2"; @@ -65,3 +67,36 @@ fn test_mkdir_dup_file() { // mkdir should fail for a file even if -p is specified. scene.ucmd().arg("-p").arg(TEST_FILE7).fails(); } + +#[test] +#[cfg(not(windows))] +fn test_symbolic_mode() { + let (at, mut ucmd) = at_and_ucmd!(); + + ucmd.arg("-m").arg("a=rwx").arg(TEST_DIR1).succeeds(); + let perms = at.metadata(TEST_DIR1).permissions().mode(); + assert_eq!(perms, 0o40777) +} + +#[test] +#[cfg(not(windows))] +fn test_symbolic_alteration() { + let (at, mut ucmd) = at_and_ucmd!(); + + ucmd.arg("-m").arg("-w").arg(TEST_DIR1).succeeds(); + let perms = at.metadata(TEST_DIR1).permissions().mode(); + assert_eq!(perms, 0o40555) +} + +#[test] +#[cfg(not(windows))] +fn test_multi_symbolic() { + let (at, mut ucmd) = at_and_ucmd!(); + + ucmd.arg("-m") + .arg("u=rwx,g=rx,o=") + .arg(TEST_DIR1) + .succeeds(); + let perms = at.metadata(TEST_DIR1).permissions().mode(); + assert_eq!(perms, 0o40750) +} diff --git a/tests/by-util/test_od.rs b/tests/by-util/test_od.rs index 0fc1d5106..6c167b325 100644 --- a/tests/by-util/test_od.rs +++ b/tests/by-util/test_od.rs @@ -1,3 +1,4 @@ +// spell-checker:ignore abcdefghijklmnopqrstuvwxyz // * This file is part of the uutils coreutils package. // * // * For the full copyright and license information, please view the LICENSE @@ -35,9 +36,10 @@ fn test_file() { { let mut f = File::create(&file).unwrap(); // spell-checker:disable-next-line - if f.write_all(b"abcdefghijklmnopqrstuvwxyz\n").is_err() { - panic!("Test setup failed - could not write file"); - } + assert!( + !f.write_all(b"abcdefghijklmnopqrstuvwxyz\n").is_err(), + "Test setup failed - could not write file" + ); } new_ucmd!() @@ -75,9 +77,10 @@ fn test_2files() { // spell-checker:disable-next-line for &(path, data) in &[(&file1, "abcdefghijklmnop"), (&file2, "qrstuvwxyz\n")] { let mut f = File::create(&path).unwrap(); - if f.write_all(data.as_bytes()).is_err() { - panic!("Test setup failed - could not write file"); - } + assert!( + !f.write_all(data.as_bytes()).is_err(), + "Test setup failed - could not write file" + ); } new_ucmd!() @@ -126,9 +129,10 @@ fn test_from_mixed() { let (data1, data2, data3) = ("abcdefg", "hijklmnop", "qrstuvwxyz\n"); for &(path, data) in &[(&file1, data1), (&file3, data3)] { let mut f = File::create(&path).unwrap(); - if f.write_all(data.as_bytes()).is_err() { - panic!("Test setup failed - could not write file"); - } + assert!( + !f.write_all(data.as_bytes()).is_err(), + "Test setup failed - could not write file" + ); } new_ucmd!() diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index 27b5f99bc..6ed3cb67d 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -1,6 +1,69 @@ use crate::common::util::*; use std::io::Read; +#[test] +fn test_hex_rejects_sign_after_identifier() { + new_ucmd!() + .args(&["0x-123ABC"]) + .fails() + .no_stdout() + .stderr_contains("invalid hexadecimal argument: '0x-123ABC'") + .stderr_contains("for more information."); + new_ucmd!() + .args(&["0x+123ABC"]) + .fails() + .no_stdout() + .stderr_contains("invalid hexadecimal argument: '0x+123ABC'") + .stderr_contains("for more information."); + new_ucmd!() + .args(&["-0x-123ABC"]) + .fails() + .no_stdout() + .stderr_contains("invalid hexadecimal argument: '-0x-123ABC'") + .stderr_contains("for more information."); + new_ucmd!() + .args(&["-0x+123ABC"]) + .fails() + .no_stdout() + .stderr_contains("invalid hexadecimal argument: '-0x+123ABC'") + .stderr_contains("for more information."); +} + +#[test] +fn test_hex_lowercase_uppercase() { + new_ucmd!() + .args(&["0xa", "0xA"]) + .succeeds() + .stdout_is("10\n"); + new_ucmd!() + .args(&["0Xa", "0XA"]) + .succeeds() + .stdout_is("10\n"); +} + +#[test] +fn test_hex_big_number() { + new_ucmd!() + .args(&[ + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "0x100000000000000000000000000000000", + ]) + .succeeds() + .stdout_is( + "340282366920938463463374607431768211455\n340282366920938463463374607431768211456\n", + ); +} + +#[test] +fn test_hex_identifier_in_wrong_place() { + new_ucmd!() + .args(&["1234ABCD0x"]) + .fails() + .no_stdout() + .stderr_contains("invalid hexadecimal argument: '1234ABCD0x'") + .stderr_contains("for more information."); +} + #[test] fn test_rejects_nan() { let ts = TestScenario::new(util_name!()); diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index c191ffcaf..cd013891b 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -145,7 +145,9 @@ fn test_invalid_utf8() { .arg("not-utf8-sequence.txt") .run() .failure() - .stderr_only("uniq: invalid utf-8 sequence of 1 bytes from index 0"); + .stderr_only( + "uniq: failed to convert line to utf8: invalid utf-8 sequence of 1 bytes from index 0", + ); } #[test] diff --git a/tests/common/util.rs b/tests/common/util.rs index bcf1086d9..c7ac816e1 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -163,25 +163,23 @@ impl CmdResult { /// asserts that the command resulted in a success (zero) status code pub fn success(&self) -> &CmdResult { - if !self.success { - panic!( - "Command was expected to succeed.\nstdout = {}\n stderr = {}", - self.stdout_str(), - self.stderr_str() - ); - } + assert!( + self.success, + "Command was expected to succeed.\nstdout = {}\n stderr = {}", + self.stdout_str(), + self.stderr_str() + ); self } /// asserts that the command resulted in a failure (non-zero) status code pub fn failure(&self) -> &CmdResult { - if self.success { - panic!( - "Command was expected to fail.\nstdout = {}\n stderr = {}", - self.stdout_str(), - self.stderr_str() - ); - } + assert!( + !self.success, + "Command was expected to fail.\nstdout = {}\n stderr = {}", + self.stdout_str(), + self.stderr_str() + ); self } @@ -197,12 +195,11 @@ impl CmdResult { /// 1. you can not know exactly what stdout will be or /// 2. you know that stdout will also be empty pub fn no_stderr(&self) -> &CmdResult { - if !self.stderr.is_empty() { - panic!( - "Expected stderr to be empty, but it's:\n{}", - self.stderr_str() - ); - } + assert!( + self.stderr.is_empty(), + "Expected stderr to be empty, but it's:\n{}", + self.stderr_str() + ); self } @@ -213,12 +210,11 @@ impl CmdResult { /// 1. you can not know exactly what stderr will be or /// 2. you know that stderr will also be empty pub fn no_stdout(&self) -> &CmdResult { - if !self.stdout.is_empty() { - panic!( - "Expected stdout to be empty, but it's:\n{}", - self.stderr_str() - ); - } + assert!( + self.stdout.is_empty(), + "Expected stdout to be empty, but it's:\n{}", + self.stderr_str() + ); self } @@ -514,37 +510,51 @@ impl AtPath { } pub fn write(&self, name: &str, contents: &str) { - log_info("open(write)", self.plus_as_string(name)); + log_info("write(default)", self.plus_as_string(name)); std::fs::write(self.plus(name), contents) .unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e)); } pub fn write_bytes(&self, name: &str, contents: &[u8]) { - log_info("open(write)", self.plus_as_string(name)); + log_info("write(default)", self.plus_as_string(name)); std::fs::write(self.plus(name), contents) .unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e)); } pub fn append(&self, name: &str, contents: &str) { - log_info("open(append)", self.plus_as_string(name)); + log_info("write(append)", self.plus_as_string(name)); let mut f = OpenOptions::new() .write(true) .append(true) + .create(true) .open(self.plus(name)) .unwrap(); f.write_all(contents.as_bytes()) - .unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e)); + .unwrap_or_else(|e| panic!("Couldn't write(append) {}: {}", name, e)); } pub fn append_bytes(&self, name: &str, contents: &[u8]) { - log_info("open(append)", self.plus_as_string(name)); + log_info("write(append)", self.plus_as_string(name)); let mut f = OpenOptions::new() .write(true) .append(true) + .create(true) .open(self.plus(name)) .unwrap(); f.write_all(contents) - .unwrap_or_else(|e| panic!("Couldn't append to {}: {}", name, e)); + .unwrap_or_else(|e| panic!("Couldn't write(append) to {}: {}", name, e)); + } + + pub fn truncate(&self, name: &str, contents: &str) { + log_info("write(truncate)", self.plus_as_string(name)); + let mut f = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(self.plus(name)) + .unwrap(); + f.write_all(contents.as_bytes()) + .unwrap_or_else(|e| panic!("Couldn't write(truncate) {}: {}", name, e)); } pub fn rename(&self, source: &str, target: &str) { @@ -570,10 +580,16 @@ impl AtPath { .unwrap_or_else(|e| panic!("Couldn't copy {:?} -> {:?}: {}", source, target, e)); } + pub fn rmdir(&self, dir: &str) { + log_info("rmdir", self.plus_as_string(dir)); + fs::remove_dir(&self.plus(dir)).unwrap(); + } + pub fn mkdir(&self, dir: &str) { log_info("mkdir", self.plus_as_string(dir)); fs::create_dir(&self.plus(dir)).unwrap(); } + pub fn mkdir_all(&self, dir: &str) { log_info("mkdir_all", self.plus_as_string(dir)); fs::create_dir_all(self.plus(dir)).unwrap(); @@ -891,9 +907,7 @@ impl UCommand { /// Add a parameter to the invocation. Path arguments are treated relative /// to the test environment directory. pub fn arg>(&mut self, arg: S) -> &mut UCommand { - if self.has_run { - panic!("{}", ALREADY_RUN); - } + assert!(!self.has_run, "{}", ALREADY_RUN); self.comm_string.push(' '); self.comm_string .push_str(arg.as_ref().to_str().unwrap_or_default()); @@ -904,9 +918,7 @@ impl UCommand { /// Add multiple parameters to the invocation. Path arguments are treated relative /// to the test environment directory. pub fn args>(&mut self, args: &[S]) -> &mut UCommand { - if self.has_run { - panic!("{}", MULTIPLE_STDIN_MEANINGLESS); - } + assert!(!self.has_run, "{}", MULTIPLE_STDIN_MEANINGLESS); let strings = args .iter() .map(|s| s.as_ref().to_os_string()) @@ -924,9 +936,11 @@ impl UCommand { /// provides standard input to feed in to the command when spawned pub fn pipe_in>>(&mut self, input: T) -> &mut UCommand { - if self.bytes_into_stdin.is_some() { - panic!("{}", MULTIPLE_STDIN_MEANINGLESS); - } + assert!( + !self.bytes_into_stdin.is_some(), + "{}", + MULTIPLE_STDIN_MEANINGLESS + ); self.bytes_into_stdin = Some(input.into()); self } @@ -941,9 +955,7 @@ impl UCommand { /// This is typically useful to test non-standard workflows /// like feeding something to a command that does not read it pub fn ignore_stdin_write_error(&mut self) -> &mut UCommand { - if self.bytes_into_stdin.is_none() { - panic!("{}", NO_STDIN_MEANINGLESS); - } + assert!(!self.bytes_into_stdin.is_none(), "{}", NO_STDIN_MEANINGLESS); self.ignore_stdin_write_error = true; self } @@ -953,9 +965,7 @@ impl UCommand { K: AsRef, V: AsRef, { - if self.has_run { - panic!("{}", ALREADY_RUN); - } + assert!(!self.has_run, "{}", ALREADY_RUN); self.raw.env(key, val); self } @@ -974,9 +984,7 @@ impl UCommand { /// Spawns the command, feeds the stdin if any, and returns the /// child process immediately. pub fn run_no_wait(&mut self) -> Child { - if self.has_run { - panic!("{}", ALREADY_RUN); - } + assert!(!self.has_run, "{}", ALREADY_RUN); self.has_run = true; log_info("run", &self.comm_string); let mut child = self diff --git a/tests/test_util_name.rs b/tests/test_util_name.rs index b0a78a2e8..76b6f4728 100644 --- a/tests/test_util_name.rs +++ b/tests/test_util_name.rs @@ -1,3 +1,4 @@ +#![allow(unused_imports)] mod common; use common::util::TestScenario; @@ -25,6 +26,7 @@ fn execution_phrase_double() { #[test] #[cfg(feature = "ls")] +#[cfg(any(unix, windows))] fn execution_phrase_single() { use std::process::Command; @@ -63,6 +65,7 @@ fn util_name_double() { #[test] #[cfg(feature = "sort")] +#[cfg(any(unix, windows))] fn util_name_single() { use std::{ io::Write, diff --git a/util/build-gnu.sh b/util/build-gnu.sh index bbb16981e..eb8293fbe 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -5,12 +5,12 @@ set -e if test ! -d ../gnu; then echo "Could not find ../gnu" - echo "git clone git@github.com:coreutils/coreutils.git gnu" + echo "git clone https://github.com:coreutils/coreutils.git gnu" exit 1 fi if test ! -d ../gnulib; then echo "Could not find ../gnulib" - echo "git clone git@github.com:coreutils/gnulib.git gnulib" + echo "git clone https://github.com/coreutils/gnulib.git gnulib" exit 1 fi diff --git a/util/publish.sh b/util/publish.sh index 0936238a8..ae171e39c 100755 --- a/util/publish.sh +++ b/util/publish.sh @@ -9,10 +9,17 @@ fi cd src/uucore/ cargo publish $ARG cd - +sleep 2s + +cd src/uucore_procs/ +cargo publish $ARG +cd - +sleep 2s cd src/uu/stdbuf/src/libstdbuf/ cargo publish $ARG cd - +sleep 2s PROGS=$(ls -1d src/uu/*/) for p in $PROGS; do diff --git a/util/update-version.sh b/util/update-version.sh index eeacd500f..cbb811300 100755 --- a/util/update-version.sh +++ b/util/update-version.sh @@ -3,14 +3,14 @@ # So, it should be triple-checked -FROM="0.0.6" -TO="0.0.7" +FROM="0.0.7" +TO="0.0.8" -UUCORE_PROCS_FROM="0.0.5" -UUCORE_PROCS_TO="0.0.6" +UUCORE_PROCS_FROM="0.0.6" +UUCORE_PROCS_TO="0.0.7" -UUCORE_FROM="0.0.8" -UUCORE_TO="0.0.9" +UUCORE_FROM="0.0.9" +UUCORE_TO="0.0.10" PROGS=$(ls -1d src/uu/*/Cargo.toml src/uu/stdbuf/src/libstdbuf/Cargo.toml Cargo.toml src/uu/base64/Cargo.toml)