From 4a7626f27a19b2bac9774e6b10ea59c5355c61c5 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 18:09:45 +0200 Subject: [PATCH 01/16] add examples --- Cargo.toml | 330 +++++++++++++++++++++---------------------- src/bin/coreutils.rs | 154 ++++++++++++++++---- 2 files changed, 288 insertions(+), 196 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cde946b68f4..b7ca5a03308 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core"] +default = ["feat_common_core", "zip"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -47,138 +47,138 @@ feat_acl = ["cp/feat_acl"] # * 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", - "ls/selinux", - "mkdir/selinux", - "mkfifo/selinux", - "mknod/selinux", - "stat/selinux", - "selinux", - "feat_require_selinux", + "cp/selinux", + "id/selinux", + "ls/selinux", + "mkdir/selinux", + "mkfifo/selinux", + "mknod/selinux", + "stat/selinux", + "selinux", + "feat_require_selinux", ] ## ## feature sets ## (common/core and Tier1) feature sets # "feat_common_core" == baseline core set of utilities which can be built/run on most targets feat_common_core = [ - "base32", - "base64", - "basename", - "basenc", - "cat", - "cksum", - "comm", - "cp", - "csplit", - "cut", - "date", - "df", - "dir", - "dircolors", - "dirname", - "dd", - "du", - "echo", - "env", - "expand", - "expr", - "factor", - "false", - "fmt", - "fold", - "hashsum", - "head", - "join", - "link", - "ln", - "ls", - "mkdir", - "mktemp", - "more", - "mv", - "nl", - "numfmt", - "od", - "paste", - "pr", - "printenv", - "printf", - "ptx", - "pwd", - "readlink", - "realpath", - "rm", - "rmdir", - "seq", - "shred", - "shuf", - "sleep", - "sort", - "split", - "sum", - "tac", - "tail", - "tee", - "test", - "tr", - "true", - "truncate", - "tsort", - "touch", - "unexpand", - "uniq", - "unlink", - "vdir", - "wc", - "yes", + "base32", + "base64", + "basename", + "basenc", + "cat", + "cksum", + "comm", + "cp", + "csplit", + "cut", + "date", + "df", + "dir", + "dircolors", + "dirname", + "dd", + "du", + "echo", + "env", + "expand", + "expr", + "factor", + "false", + "fmt", + "fold", + "hashsum", + "head", + "join", + "link", + "ln", + "ls", + "mkdir", + "mktemp", + "more", + "mv", + "nl", + "numfmt", + "od", + "paste", + "pr", + "printenv", + "printf", + "ptx", + "pwd", + "readlink", + "realpath", + "rm", + "rmdir", + "seq", + "shred", + "shuf", + "sleep", + "sort", + "split", + "sum", + "tac", + "tail", + "tee", + "test", + "tr", + "true", + "truncate", + "tsort", + "touch", + "unexpand", + "uniq", + "unlink", + "vdir", + "wc", + "yes", ] # "feat_Tier1" == expanded set of utilities which can be built/run on the usual rust "Tier 1" target platforms (ref: ) feat_Tier1 = [ - "feat_common_core", - # - "arch", - "hostname", - "nproc", - "sync", - "touch", - "uname", - "whoami", + "feat_common_core", + # + "arch", + "hostname", + "nproc", + "sync", + "touch", + "uname", + "whoami", ] ## (primary platforms) feature sets # "feat_os_macos" == set of utilities which can be built/run on the MacOS platform feat_os_macos = [ - "feat_os_unix", ## == a modern/usual *nix platform - # - "feat_require_unix_hostid", + "feat_os_unix", ## == a modern/usual *nix platform + # + "feat_require_unix_hostid", ] # "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms. # Also used for targets binding to the "musl" library (ref: ) feat_os_unix = [ - "feat_Tier1", - # - "feat_require_crate_cpp", - "feat_require_unix", - "feat_require_unix_utmpx", - "feat_require_unix_hostid", + "feat_Tier1", + # + "feat_require_crate_cpp", + "feat_require_unix", + "feat_require_unix_utmpx", + "feat_require_unix_hostid", ] # "feat_os_windows" == set of utilities which can be built/run on modern/usual windows platforms feat_os_windows = [ - "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" + "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" ] ## (secondary platforms) feature sets # "feat_os_unix_gnueabihf" == set of utilities which can be built/run on the "arm-unknown-linux-gnueabihf" target (ARMv6 Linux [hardfloat]) feat_os_unix_gnueabihf = [ - "feat_Tier1", - # - "feat_require_unix", - "feat_require_unix_hostid", - "feat_require_unix_utmpx", + "feat_Tier1", + # + "feat_require_unix", + "feat_require_unix_hostid", + "feat_require_unix_utmpx", ] feat_os_unix_android = [ - "feat_Tier1", - # - "feat_require_unix", + "feat_Tier1", + # + "feat_require_unix", ] ## feature sets with requirements (restricting cross-platform availability) # @@ -188,24 +188,24 @@ feat_os_unix_android = [ feat_require_crate_cpp = ["stdbuf"] # "feat_require_unix" == set of utilities requiring support which is only available on unix platforms (as of 2020-04-23) feat_require_unix = [ - "chgrp", - "chmod", - "chown", - "chroot", - "groups", - "id", - "install", - "kill", - "logname", - "mkfifo", - "mknod", - "nice", - "nohup", - "pathchk", - "stat", - "stty", - "timeout", - "tty", + "chgrp", + "chmod", + "chown", + "chroot", + "groups", + "id", + "install", + "kill", + "logname", + "mkfifo", + "mknod", + "nice", + "nohup", + "pathchk", + "stat", + "stty", + "timeout", + "tty", ] # "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support # * ref: @@ -217,43 +217,43 @@ feat_require_selinux = ["chcon", "runcon"] ## (alternate/newer/smaller platforms) feature sets # "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: ; ) feat_os_unix_fuchsia = [ - "feat_common_core", - # - "feat_require_crate_cpp", - # - "chgrp", - "chmod", - "chown", - "du", - "groups", - "hostid", - "install", - "logname", - "mkfifo", - "mknod", - "nice", - "pathchk", - "tty", - "uname", - "unlink", + "feat_common_core", + # + "feat_require_crate_cpp", + # + "chgrp", + "chmod", + "chown", + "du", + "groups", + "hostid", + "install", + "logname", + "mkfifo", + "mknod", + "nice", + "pathchk", + "tty", + "uname", + "unlink", ] # "feat_os_unix_redox" == set of utilities which can be built/run on "Redox OS" (refs: ; ) feat_os_unix_redox = [ - "feat_common_core", - # - "chmod", - "stat", - "uname", + "feat_common_core", + # + "chmod", + "stat", + "uname", ] # "feat_os_windows_legacy" == slightly restricted set of utilities which can be built/run on early windows platforms (eg, "WinXP") feat_os_windows_legacy = [ - "feat_common_core", - # - "arch", - "nproc", - "sync", - "touch", - "whoami", + "feat_common_core", + # + "arch", + "nproc", + "sync", + "touch", + "whoami", ] ## # * bypass/override ~ translate 'test' feature name to avoid dependency collision with rust core 'test' crate (o/w surfaces as compiler errors during testing) @@ -277,9 +277,9 @@ bstr = "1.9.1" bytecount = "0.6.8" byteorder = "1.5.0" chrono = { version = "0.4.38", default-features = false, features = [ - "std", - "alloc", - "clock", + "std", + "alloc", + "clock", ] } chrono-tz = "0.10.0" clap = { version = "4.5", features = ["wrap_help", "cargo"] } @@ -306,7 +306,7 @@ itertools = "0.14.0" libc = "0.2.172" linux-raw-sys = "0.9" lscolors = { version = "0.20.0", default-features = false, features = [ - "gnu_legacy", + "gnu_legacy", ] } memchr = "2.7.2" memmap2 = "0.9.4" @@ -509,11 +509,11 @@ time = { workspace = true, features = ["local-offset"] } unindent = "0.2.3" uutests = { workspace = true } uucore = { workspace = true, features = [ - "mode", - "entries", - "process", - "signals", - "utmpx", + "mode", + "entries", + "process", + "signals", + "utmpx", ] } walkdir = { workspace = true } hex-literal = "1.0.0" diff --git a/src/bin/coreutils.rs b/src/bin/coreutils.rs index b29e7ea2337..c9064189772 100644 --- a/src/bin/coreutils.rs +++ b/src/bin/coreutils.rs @@ -10,19 +10,34 @@ use clap_complete::Shell; use std::cmp; use std::ffi::OsStr; use std::ffi::OsString; +use std::fs::File; +use std::io::Read; +use std::io::Seek; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process; use uucore::display::Quotable; +use zip::ZipArchive; const VERSION: &str = env!("CARGO_PKG_VERSION"); +const COMPLETION: &str = "completion"; +const MANPAGE: &str = "manpage"; + include!(concat!(env!("OUT_DIR"), "/uutils_map.rs")); fn usage(utils: &UtilityMap, name: &str) { println!("{name} {VERSION} (multi-call binary)\n"); println!("Usage: {name} [function [arguments...]]"); - println!(" {name} --list\n"); + println!(" {name} --list"); + println!(); + println!("Functions:"); + println!(" {COMPLETION}",); + println!(" {}", get_completion_args(utils).render_usage()); + println!(" '{MANPAGE}'",); + println!(" {}", get_manpage_args(utils).render_usage()); + println!(" '' [arguments...]"); + println!(); println!("Options:"); println!(" --list lists all defined functions, one per row\n"); println!("Currently defined functions:\n"); @@ -95,8 +110,14 @@ fn main() { }; match util { - "completion" => gen_completions(args, &utils), - "manpage" => gen_manpage(args, &utils), + COMPLETION => { + gen_completions(args, &utils); + process::exit(0); + } + MANPAGE => { + gen_manpage(args, &utils); + process::exit(0); + } "--list" => { let mut utils: Vec<_> = utils.keys().collect(); utils.sort(); @@ -148,18 +169,11 @@ fn main() { } } -/// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout -/// # Panics -/// Panics if the utility map is empty -fn gen_completions( - args: impl Iterator, - util_map: &UtilityMap, -) -> ! { +fn get_completion_args(util_map: &UtilityMap) -> clap::Command { let all_utilities: Vec<_> = std::iter::once("coreutils") .chain(util_map.keys().copied()) .collect(); - - let matches = Command::new("completion") + Command::new(COMPLETION) .about("Prints completions to stdout") .arg( Arg::new("utility") @@ -171,7 +185,17 @@ fn gen_completions( .value_parser(clap::builder::EnumValueParser::::new()) .required(true), ) - .get_matches_from(std::iter::once(OsString::from("completion")).chain(args)); +} + +/// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout +/// # Panics +/// Panics if the utility map is empty +fn gen_completions( + args: impl Iterator, + util_map: &UtilityMap, +) { + let matches = get_completion_args(util_map) + .get_matches_from(std::iter::once(OsString::from(COMPLETION)).chain(args)); let utility = matches.get_one::("utility").unwrap(); let shell = *matches.get_one::("shell").unwrap(); @@ -185,42 +209,49 @@ fn gen_completions( clap_complete::generate(shell, &mut command, bin_name, &mut io::stdout()); io::stdout().flush().unwrap(); - process::exit(0); } -/// Generate the manpage for the utility in the first parameter -/// # Panics -/// Panics if the utility map is empty -fn gen_manpage( - args: impl Iterator, - util_map: &UtilityMap, -) -> ! { +fn get_manpage_args(util_map: &UtilityMap) -> clap::Command { let all_utilities: Vec<_> = std::iter::once("coreutils") .chain(util_map.keys().copied()) .collect(); + Command::new(MANPAGE).about("Prints manpage to stdout").arg( + Arg::new("utility") + .value_parser(clap::builder::PossibleValuesParser::new(all_utilities)) + .required(true), + ) +} - let matches = Command::new("manpage") - .about("Prints manpage to stdout") - .arg( - Arg::new("utility") - .value_parser(clap::builder::PossibleValuesParser::new(all_utilities)) - .required(true), - ) - .get_matches_from(std::iter::once(OsString::from("manpage")).chain(args)); +/// Generate the manpage for the utility in the first parameter +/// # Panics +/// Panics if the utility map is empty +fn gen_manpage(args: impl Iterator, util_map: &UtilityMap) { + let tldr_zip = File::open("docs/tldr.zip") + .ok() + .and_then(|f| ZipArchive::new(f).ok()); + + if tldr_zip.is_none() { + // Could not open tldr.zip + } + let matches = get_manpage_args(util_map) + .get_matches_from(std::iter::once(OsString::from(MANPAGE)).chain(args)); let utility = matches.get_one::("utility").unwrap(); let command = if utility == "coreutils" { gen_coreutils_app(util_map) } else { - util_map.get(utility).unwrap().1() + let mut cmd = util_map.get(utility).unwrap().1(); + if let Ok(examples) = get_zip_examples(utility) { + cmd = cmd.after_help(examples); + } + cmd }; let man = clap_mangen::Man::new(command); man.render(&mut io::stdout()) .expect("Man page generation failed"); io::stdout().flush().unwrap(); - process::exit(0); } /// # Panics @@ -239,3 +270,64 @@ fn gen_coreutils_app(util_map: &UtilityMap) -> Command { } command } + +/// # Errors +/// Returns an error if the tldr.zip file cannot be opened or read +fn get_zip_examples(name: &str) -> io::Result { + fn get_zip_content(archive: &mut ZipArchive, name: &str) -> Option { + let mut s = String::new(); + archive.by_name(name).ok()?.read_to_string(&mut s).unwrap(); + Some(s) + } + + let mut w = io::BufWriter::new(Vec::new()); + let file = File::open("docs/tldr.zip")?; + let mut tldr_zip = match ZipArchive::new(file) { + Ok(zip) => zip, + Err(e) => { + return Err(io::Error::new( + io::ErrorKind::NotFound, + format!("Error reading tldr.zip: {}", e), + )); + } + }; + + let content = if let Some(f) = + get_zip_content(&mut tldr_zip, &format!("pages/common/{}.md", name)) + { + f + } else if let Some(f) = get_zip_content(&mut tldr_zip, &format!("pages/linux/{}.md", name)) { + f + } else { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "Could not find tldr examples", + )); + }; + + writeln!(w, "Examples")?; + writeln!(w)?; + for line in content.lines().skip_while(|l| !l.starts_with('-')) { + if let Some(l) = line.strip_prefix("- ") { + writeln!(w, "{l}")?; + } else if line.starts_with('`') { + writeln!(w, "{}", line.trim_matches('`'))?; + } else if line.is_empty() { + writeln!(w)?; + } else { + // println!("Not sure what to do with this line:"); + // println!("{line}"); + } + } + writeln!(w)?; + writeln!( + w, + "> The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md)." + )?; + writeln!(w, "\n\n\n")?; + writeln!( + w, + "> Please note that, as uutils is a work in progress, some examples might fail." + )?; + Ok(String::from_utf8(w.into_inner().unwrap()).unwrap()) +} From 78d0b99a0ea201af538b843b85f4c8ac03e5457c Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 18:11:58 +0200 Subject: [PATCH 02/16] fix: space --- Cargo.toml | 328 ++++++++++++++++++++++++++--------------------------- 1 file changed, 164 insertions(+), 164 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7ca5a03308..d8582c989fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,138 +47,138 @@ feat_acl = ["cp/feat_acl"] # * 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", - "ls/selinux", - "mkdir/selinux", - "mkfifo/selinux", - "mknod/selinux", - "stat/selinux", - "selinux", - "feat_require_selinux", + "cp/selinux", + "id/selinux", + "ls/selinux", + "mkdir/selinux", + "mkfifo/selinux", + "mknod/selinux", + "stat/selinux", + "selinux", + "feat_require_selinux", ] ## ## feature sets ## (common/core and Tier1) feature sets # "feat_common_core" == baseline core set of utilities which can be built/run on most targets feat_common_core = [ - "base32", - "base64", - "basename", - "basenc", - "cat", - "cksum", - "comm", - "cp", - "csplit", - "cut", - "date", - "df", - "dir", - "dircolors", - "dirname", - "dd", - "du", - "echo", - "env", - "expand", - "expr", - "factor", - "false", - "fmt", - "fold", - "hashsum", - "head", - "join", - "link", - "ln", - "ls", - "mkdir", - "mktemp", - "more", - "mv", - "nl", - "numfmt", - "od", - "paste", - "pr", - "printenv", - "printf", - "ptx", - "pwd", - "readlink", - "realpath", - "rm", - "rmdir", - "seq", - "shred", - "shuf", - "sleep", - "sort", - "split", - "sum", - "tac", - "tail", - "tee", - "test", - "tr", - "true", - "truncate", - "tsort", - "touch", - "unexpand", - "uniq", - "unlink", - "vdir", - "wc", - "yes", + "base32", + "base64", + "basename", + "basenc", + "cat", + "cksum", + "comm", + "cp", + "csplit", + "cut", + "date", + "df", + "dir", + "dircolors", + "dirname", + "dd", + "du", + "echo", + "env", + "expand", + "expr", + "factor", + "false", + "fmt", + "fold", + "hashsum", + "head", + "join", + "link", + "ln", + "ls", + "mkdir", + "mktemp", + "more", + "mv", + "nl", + "numfmt", + "od", + "paste", + "pr", + "printenv", + "printf", + "ptx", + "pwd", + "readlink", + "realpath", + "rm", + "rmdir", + "seq", + "shred", + "shuf", + "sleep", + "sort", + "split", + "sum", + "tac", + "tail", + "tee", + "test", + "tr", + "true", + "truncate", + "tsort", + "touch", + "unexpand", + "uniq", + "unlink", + "vdir", + "wc", + "yes", ] # "feat_Tier1" == expanded set of utilities which can be built/run on the usual rust "Tier 1" target platforms (ref: ) feat_Tier1 = [ - "feat_common_core", - # - "arch", - "hostname", - "nproc", - "sync", - "touch", - "uname", - "whoami", + "feat_common_core", + # + "arch", + "hostname", + "nproc", + "sync", + "touch", + "uname", + "whoami", ] ## (primary platforms) feature sets # "feat_os_macos" == set of utilities which can be built/run on the MacOS platform feat_os_macos = [ - "feat_os_unix", ## == a modern/usual *nix platform - # - "feat_require_unix_hostid", + "feat_os_unix", ## == a modern/usual *nix platform + # + "feat_require_unix_hostid", ] # "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms. # Also used for targets binding to the "musl" library (ref: ) feat_os_unix = [ - "feat_Tier1", - # - "feat_require_crate_cpp", - "feat_require_unix", - "feat_require_unix_utmpx", - "feat_require_unix_hostid", + "feat_Tier1", + # + "feat_require_crate_cpp", + "feat_require_unix", + "feat_require_unix_utmpx", + "feat_require_unix_hostid", ] # "feat_os_windows" == set of utilities which can be built/run on modern/usual windows platforms feat_os_windows = [ - "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" + "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" ] ## (secondary platforms) feature sets # "feat_os_unix_gnueabihf" == set of utilities which can be built/run on the "arm-unknown-linux-gnueabihf" target (ARMv6 Linux [hardfloat]) feat_os_unix_gnueabihf = [ - "feat_Tier1", - # - "feat_require_unix", - "feat_require_unix_hostid", - "feat_require_unix_utmpx", + "feat_Tier1", + # + "feat_require_unix", + "feat_require_unix_hostid", + "feat_require_unix_utmpx", ] feat_os_unix_android = [ - "feat_Tier1", - # - "feat_require_unix", + "feat_Tier1", + # + "feat_require_unix", ] ## feature sets with requirements (restricting cross-platform availability) # @@ -188,24 +188,24 @@ feat_os_unix_android = [ feat_require_crate_cpp = ["stdbuf"] # "feat_require_unix" == set of utilities requiring support which is only available on unix platforms (as of 2020-04-23) feat_require_unix = [ - "chgrp", - "chmod", - "chown", - "chroot", - "groups", - "id", - "install", - "kill", - "logname", - "mkfifo", - "mknod", - "nice", - "nohup", - "pathchk", - "stat", - "stty", - "timeout", - "tty", + "chgrp", + "chmod", + "chown", + "chroot", + "groups", + "id", + "install", + "kill", + "logname", + "mkfifo", + "mknod", + "nice", + "nohup", + "pathchk", + "stat", + "stty", + "timeout", + "tty", ] # "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support # * ref: @@ -217,43 +217,43 @@ feat_require_selinux = ["chcon", "runcon"] ## (alternate/newer/smaller platforms) feature sets # "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: ; ) feat_os_unix_fuchsia = [ - "feat_common_core", - # - "feat_require_crate_cpp", - # - "chgrp", - "chmod", - "chown", - "du", - "groups", - "hostid", - "install", - "logname", - "mkfifo", - "mknod", - "nice", - "pathchk", - "tty", - "uname", - "unlink", + "feat_common_core", + # + "feat_require_crate_cpp", + # + "chgrp", + "chmod", + "chown", + "du", + "groups", + "hostid", + "install", + "logname", + "mkfifo", + "mknod", + "nice", + "pathchk", + "tty", + "uname", + "unlink", ] # "feat_os_unix_redox" == set of utilities which can be built/run on "Redox OS" (refs: ; ) feat_os_unix_redox = [ - "feat_common_core", - # - "chmod", - "stat", - "uname", + "feat_common_core", + # + "chmod", + "stat", + "uname", ] # "feat_os_windows_legacy" == slightly restricted set of utilities which can be built/run on early windows platforms (eg, "WinXP") feat_os_windows_legacy = [ - "feat_common_core", - # - "arch", - "nproc", - "sync", - "touch", - "whoami", + "feat_common_core", + # + "arch", + "nproc", + "sync", + "touch", + "whoami", ] ## # * bypass/override ~ translate 'test' feature name to avoid dependency collision with rust core 'test' crate (o/w surfaces as compiler errors during testing) @@ -277,9 +277,9 @@ bstr = "1.9.1" bytecount = "0.6.8" byteorder = "1.5.0" chrono = { version = "0.4.38", default-features = false, features = [ - "std", - "alloc", - "clock", + "std", + "alloc", + "clock", ] } chrono-tz = "0.10.0" clap = { version = "4.5", features = ["wrap_help", "cargo"] } @@ -306,7 +306,7 @@ itertools = "0.14.0" libc = "0.2.172" linux-raw-sys = "0.9" lscolors = { version = "0.20.0", default-features = false, features = [ - "gnu_legacy", + "gnu_legacy", ] } memchr = "2.7.2" memmap2 = "0.9.4" @@ -509,11 +509,11 @@ time = { workspace = true, features = ["local-offset"] } unindent = "0.2.3" uutests = { workspace = true } uucore = { workspace = true, features = [ - "mode", - "entries", - "process", - "signals", - "utmpx", + "mode", + "entries", + "process", + "signals", + "utmpx", ] } walkdir = { workspace = true } hex-literal = "1.0.0" From 8d2a9c1a12d56184e67f374beb98f89b7c118552 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 22:51:28 +0200 Subject: [PATCH 03/16] fix features flag --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d8582c989fb..427b8995093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core", "zip"] +default = ["feat_common_core", "dep:zip"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -35,7 +35,7 @@ expensive_tests = [] # "test_risky_names" == enable tests that create problematic file names (would make a network share inaccessible to Windows, breaks SVN on Mac OS, etc.) test_risky_names = [] # * only build `uudoc` when `--feature uudoc` is activated -uudoc = ["zip", "dep:uuhelp_parser"] +uudoc = ["dep:zip", "dep:uuhelp_parser"] ## features # "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) # NOTE: @@ -542,6 +542,7 @@ phf_codegen = { workspace = true } [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" +required-features = ["default"] [[bin]] name = "uudoc" From f01e40b17a3666cb94a9becd7512267bedeead26 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 23:00:47 +0200 Subject: [PATCH 04/16] change required feature --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 427b8995093..6125ea8423b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core", "dep:zip"] +default = ["feat_common_core"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -36,6 +36,7 @@ expensive_tests = [] test_risky_names = [] # * only build `uudoc` when `--feature uudoc` is activated uudoc = ["dep:zip", "dep:uuhelp_parser"] +coreutils = ["dep:zip"] ## features # "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) # NOTE: @@ -542,7 +543,7 @@ phf_codegen = { workspace = true } [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" -required-features = ["default"] +required-features = ["coreutils"] [[bin]] name = "uudoc" From 5bdafc62810607008a35fb4680a48a6eb6ead337 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 23:07:19 +0200 Subject: [PATCH 05/16] depencies --- Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6125ea8423b..427b8995093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core"] +default = ["feat_common_core", "dep:zip"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -36,7 +36,6 @@ expensive_tests = [] test_risky_names = [] # * only build `uudoc` when `--feature uudoc` is activated uudoc = ["dep:zip", "dep:uuhelp_parser"] -coreutils = ["dep:zip"] ## features # "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) # NOTE: @@ -543,7 +542,7 @@ phf_codegen = { workspace = true } [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" -required-features = ["coreutils"] +required-features = ["default"] [[bin]] name = "uudoc" From 1063992b225fdece929c6178848d4a087290bb73 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 18:09:45 +0200 Subject: [PATCH 06/16] add examples --- Cargo.toml | 330 +++++++++++++++++++++---------------------- src/bin/coreutils.rs | 154 ++++++++++++++++---- 2 files changed, 288 insertions(+), 196 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cde946b68f4..b7ca5a03308 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core"] +default = ["feat_common_core", "zip"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -47,138 +47,138 @@ feat_acl = ["cp/feat_acl"] # * 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", - "ls/selinux", - "mkdir/selinux", - "mkfifo/selinux", - "mknod/selinux", - "stat/selinux", - "selinux", - "feat_require_selinux", + "cp/selinux", + "id/selinux", + "ls/selinux", + "mkdir/selinux", + "mkfifo/selinux", + "mknod/selinux", + "stat/selinux", + "selinux", + "feat_require_selinux", ] ## ## feature sets ## (common/core and Tier1) feature sets # "feat_common_core" == baseline core set of utilities which can be built/run on most targets feat_common_core = [ - "base32", - "base64", - "basename", - "basenc", - "cat", - "cksum", - "comm", - "cp", - "csplit", - "cut", - "date", - "df", - "dir", - "dircolors", - "dirname", - "dd", - "du", - "echo", - "env", - "expand", - "expr", - "factor", - "false", - "fmt", - "fold", - "hashsum", - "head", - "join", - "link", - "ln", - "ls", - "mkdir", - "mktemp", - "more", - "mv", - "nl", - "numfmt", - "od", - "paste", - "pr", - "printenv", - "printf", - "ptx", - "pwd", - "readlink", - "realpath", - "rm", - "rmdir", - "seq", - "shred", - "shuf", - "sleep", - "sort", - "split", - "sum", - "tac", - "tail", - "tee", - "test", - "tr", - "true", - "truncate", - "tsort", - "touch", - "unexpand", - "uniq", - "unlink", - "vdir", - "wc", - "yes", + "base32", + "base64", + "basename", + "basenc", + "cat", + "cksum", + "comm", + "cp", + "csplit", + "cut", + "date", + "df", + "dir", + "dircolors", + "dirname", + "dd", + "du", + "echo", + "env", + "expand", + "expr", + "factor", + "false", + "fmt", + "fold", + "hashsum", + "head", + "join", + "link", + "ln", + "ls", + "mkdir", + "mktemp", + "more", + "mv", + "nl", + "numfmt", + "od", + "paste", + "pr", + "printenv", + "printf", + "ptx", + "pwd", + "readlink", + "realpath", + "rm", + "rmdir", + "seq", + "shred", + "shuf", + "sleep", + "sort", + "split", + "sum", + "tac", + "tail", + "tee", + "test", + "tr", + "true", + "truncate", + "tsort", + "touch", + "unexpand", + "uniq", + "unlink", + "vdir", + "wc", + "yes", ] # "feat_Tier1" == expanded set of utilities which can be built/run on the usual rust "Tier 1" target platforms (ref: ) feat_Tier1 = [ - "feat_common_core", - # - "arch", - "hostname", - "nproc", - "sync", - "touch", - "uname", - "whoami", + "feat_common_core", + # + "arch", + "hostname", + "nproc", + "sync", + "touch", + "uname", + "whoami", ] ## (primary platforms) feature sets # "feat_os_macos" == set of utilities which can be built/run on the MacOS platform feat_os_macos = [ - "feat_os_unix", ## == a modern/usual *nix platform - # - "feat_require_unix_hostid", + "feat_os_unix", ## == a modern/usual *nix platform + # + "feat_require_unix_hostid", ] # "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms. # Also used for targets binding to the "musl" library (ref: ) feat_os_unix = [ - "feat_Tier1", - # - "feat_require_crate_cpp", - "feat_require_unix", - "feat_require_unix_utmpx", - "feat_require_unix_hostid", + "feat_Tier1", + # + "feat_require_crate_cpp", + "feat_require_unix", + "feat_require_unix_utmpx", + "feat_require_unix_hostid", ] # "feat_os_windows" == set of utilities which can be built/run on modern/usual windows platforms feat_os_windows = [ - "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" + "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" ] ## (secondary platforms) feature sets # "feat_os_unix_gnueabihf" == set of utilities which can be built/run on the "arm-unknown-linux-gnueabihf" target (ARMv6 Linux [hardfloat]) feat_os_unix_gnueabihf = [ - "feat_Tier1", - # - "feat_require_unix", - "feat_require_unix_hostid", - "feat_require_unix_utmpx", + "feat_Tier1", + # + "feat_require_unix", + "feat_require_unix_hostid", + "feat_require_unix_utmpx", ] feat_os_unix_android = [ - "feat_Tier1", - # - "feat_require_unix", + "feat_Tier1", + # + "feat_require_unix", ] ## feature sets with requirements (restricting cross-platform availability) # @@ -188,24 +188,24 @@ feat_os_unix_android = [ feat_require_crate_cpp = ["stdbuf"] # "feat_require_unix" == set of utilities requiring support which is only available on unix platforms (as of 2020-04-23) feat_require_unix = [ - "chgrp", - "chmod", - "chown", - "chroot", - "groups", - "id", - "install", - "kill", - "logname", - "mkfifo", - "mknod", - "nice", - "nohup", - "pathchk", - "stat", - "stty", - "timeout", - "tty", + "chgrp", + "chmod", + "chown", + "chroot", + "groups", + "id", + "install", + "kill", + "logname", + "mkfifo", + "mknod", + "nice", + "nohup", + "pathchk", + "stat", + "stty", + "timeout", + "tty", ] # "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support # * ref: @@ -217,43 +217,43 @@ feat_require_selinux = ["chcon", "runcon"] ## (alternate/newer/smaller platforms) feature sets # "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: ; ) feat_os_unix_fuchsia = [ - "feat_common_core", - # - "feat_require_crate_cpp", - # - "chgrp", - "chmod", - "chown", - "du", - "groups", - "hostid", - "install", - "logname", - "mkfifo", - "mknod", - "nice", - "pathchk", - "tty", - "uname", - "unlink", + "feat_common_core", + # + "feat_require_crate_cpp", + # + "chgrp", + "chmod", + "chown", + "du", + "groups", + "hostid", + "install", + "logname", + "mkfifo", + "mknod", + "nice", + "pathchk", + "tty", + "uname", + "unlink", ] # "feat_os_unix_redox" == set of utilities which can be built/run on "Redox OS" (refs: ; ) feat_os_unix_redox = [ - "feat_common_core", - # - "chmod", - "stat", - "uname", + "feat_common_core", + # + "chmod", + "stat", + "uname", ] # "feat_os_windows_legacy" == slightly restricted set of utilities which can be built/run on early windows platforms (eg, "WinXP") feat_os_windows_legacy = [ - "feat_common_core", - # - "arch", - "nproc", - "sync", - "touch", - "whoami", + "feat_common_core", + # + "arch", + "nproc", + "sync", + "touch", + "whoami", ] ## # * bypass/override ~ translate 'test' feature name to avoid dependency collision with rust core 'test' crate (o/w surfaces as compiler errors during testing) @@ -277,9 +277,9 @@ bstr = "1.9.1" bytecount = "0.6.8" byteorder = "1.5.0" chrono = { version = "0.4.38", default-features = false, features = [ - "std", - "alloc", - "clock", + "std", + "alloc", + "clock", ] } chrono-tz = "0.10.0" clap = { version = "4.5", features = ["wrap_help", "cargo"] } @@ -306,7 +306,7 @@ itertools = "0.14.0" libc = "0.2.172" linux-raw-sys = "0.9" lscolors = { version = "0.20.0", default-features = false, features = [ - "gnu_legacy", + "gnu_legacy", ] } memchr = "2.7.2" memmap2 = "0.9.4" @@ -509,11 +509,11 @@ time = { workspace = true, features = ["local-offset"] } unindent = "0.2.3" uutests = { workspace = true } uucore = { workspace = true, features = [ - "mode", - "entries", - "process", - "signals", - "utmpx", + "mode", + "entries", + "process", + "signals", + "utmpx", ] } walkdir = { workspace = true } hex-literal = "1.0.0" diff --git a/src/bin/coreutils.rs b/src/bin/coreutils.rs index b29e7ea2337..c9064189772 100644 --- a/src/bin/coreutils.rs +++ b/src/bin/coreutils.rs @@ -10,19 +10,34 @@ use clap_complete::Shell; use std::cmp; use std::ffi::OsStr; use std::ffi::OsString; +use std::fs::File; +use std::io::Read; +use std::io::Seek; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process; use uucore::display::Quotable; +use zip::ZipArchive; const VERSION: &str = env!("CARGO_PKG_VERSION"); +const COMPLETION: &str = "completion"; +const MANPAGE: &str = "manpage"; + include!(concat!(env!("OUT_DIR"), "/uutils_map.rs")); fn usage(utils: &UtilityMap, name: &str) { println!("{name} {VERSION} (multi-call binary)\n"); println!("Usage: {name} [function [arguments...]]"); - println!(" {name} --list\n"); + println!(" {name} --list"); + println!(); + println!("Functions:"); + println!(" {COMPLETION}",); + println!(" {}", get_completion_args(utils).render_usage()); + println!(" '{MANPAGE}'",); + println!(" {}", get_manpage_args(utils).render_usage()); + println!(" '' [arguments...]"); + println!(); println!("Options:"); println!(" --list lists all defined functions, one per row\n"); println!("Currently defined functions:\n"); @@ -95,8 +110,14 @@ fn main() { }; match util { - "completion" => gen_completions(args, &utils), - "manpage" => gen_manpage(args, &utils), + COMPLETION => { + gen_completions(args, &utils); + process::exit(0); + } + MANPAGE => { + gen_manpage(args, &utils); + process::exit(0); + } "--list" => { let mut utils: Vec<_> = utils.keys().collect(); utils.sort(); @@ -148,18 +169,11 @@ fn main() { } } -/// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout -/// # Panics -/// Panics if the utility map is empty -fn gen_completions( - args: impl Iterator, - util_map: &UtilityMap, -) -> ! { +fn get_completion_args(util_map: &UtilityMap) -> clap::Command { let all_utilities: Vec<_> = std::iter::once("coreutils") .chain(util_map.keys().copied()) .collect(); - - let matches = Command::new("completion") + Command::new(COMPLETION) .about("Prints completions to stdout") .arg( Arg::new("utility") @@ -171,7 +185,17 @@ fn gen_completions( .value_parser(clap::builder::EnumValueParser::::new()) .required(true), ) - .get_matches_from(std::iter::once(OsString::from("completion")).chain(args)); +} + +/// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout +/// # Panics +/// Panics if the utility map is empty +fn gen_completions( + args: impl Iterator, + util_map: &UtilityMap, +) { + let matches = get_completion_args(util_map) + .get_matches_from(std::iter::once(OsString::from(COMPLETION)).chain(args)); let utility = matches.get_one::("utility").unwrap(); let shell = *matches.get_one::("shell").unwrap(); @@ -185,42 +209,49 @@ fn gen_completions( clap_complete::generate(shell, &mut command, bin_name, &mut io::stdout()); io::stdout().flush().unwrap(); - process::exit(0); } -/// Generate the manpage for the utility in the first parameter -/// # Panics -/// Panics if the utility map is empty -fn gen_manpage( - args: impl Iterator, - util_map: &UtilityMap, -) -> ! { +fn get_manpage_args(util_map: &UtilityMap) -> clap::Command { let all_utilities: Vec<_> = std::iter::once("coreutils") .chain(util_map.keys().copied()) .collect(); + Command::new(MANPAGE).about("Prints manpage to stdout").arg( + Arg::new("utility") + .value_parser(clap::builder::PossibleValuesParser::new(all_utilities)) + .required(true), + ) +} - let matches = Command::new("manpage") - .about("Prints manpage to stdout") - .arg( - Arg::new("utility") - .value_parser(clap::builder::PossibleValuesParser::new(all_utilities)) - .required(true), - ) - .get_matches_from(std::iter::once(OsString::from("manpage")).chain(args)); +/// Generate the manpage for the utility in the first parameter +/// # Panics +/// Panics if the utility map is empty +fn gen_manpage(args: impl Iterator, util_map: &UtilityMap) { + let tldr_zip = File::open("docs/tldr.zip") + .ok() + .and_then(|f| ZipArchive::new(f).ok()); + + if tldr_zip.is_none() { + // Could not open tldr.zip + } + let matches = get_manpage_args(util_map) + .get_matches_from(std::iter::once(OsString::from(MANPAGE)).chain(args)); let utility = matches.get_one::("utility").unwrap(); let command = if utility == "coreutils" { gen_coreutils_app(util_map) } else { - util_map.get(utility).unwrap().1() + let mut cmd = util_map.get(utility).unwrap().1(); + if let Ok(examples) = get_zip_examples(utility) { + cmd = cmd.after_help(examples); + } + cmd }; let man = clap_mangen::Man::new(command); man.render(&mut io::stdout()) .expect("Man page generation failed"); io::stdout().flush().unwrap(); - process::exit(0); } /// # Panics @@ -239,3 +270,64 @@ fn gen_coreutils_app(util_map: &UtilityMap) -> Command { } command } + +/// # Errors +/// Returns an error if the tldr.zip file cannot be opened or read +fn get_zip_examples(name: &str) -> io::Result { + fn get_zip_content(archive: &mut ZipArchive, name: &str) -> Option { + let mut s = String::new(); + archive.by_name(name).ok()?.read_to_string(&mut s).unwrap(); + Some(s) + } + + let mut w = io::BufWriter::new(Vec::new()); + let file = File::open("docs/tldr.zip")?; + let mut tldr_zip = match ZipArchive::new(file) { + Ok(zip) => zip, + Err(e) => { + return Err(io::Error::new( + io::ErrorKind::NotFound, + format!("Error reading tldr.zip: {}", e), + )); + } + }; + + let content = if let Some(f) = + get_zip_content(&mut tldr_zip, &format!("pages/common/{}.md", name)) + { + f + } else if let Some(f) = get_zip_content(&mut tldr_zip, &format!("pages/linux/{}.md", name)) { + f + } else { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "Could not find tldr examples", + )); + }; + + writeln!(w, "Examples")?; + writeln!(w)?; + for line in content.lines().skip_while(|l| !l.starts_with('-')) { + if let Some(l) = line.strip_prefix("- ") { + writeln!(w, "{l}")?; + } else if line.starts_with('`') { + writeln!(w, "{}", line.trim_matches('`'))?; + } else if line.is_empty() { + writeln!(w)?; + } else { + // println!("Not sure what to do with this line:"); + // println!("{line}"); + } + } + writeln!(w)?; + writeln!( + w, + "> The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md)." + )?; + writeln!(w, "\n\n\n")?; + writeln!( + w, + "> Please note that, as uutils is a work in progress, some examples might fail." + )?; + Ok(String::from_utf8(w.into_inner().unwrap()).unwrap()) +} From a46a7742088ee41ad2c531db0694a5fec5ec2d4b Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 18:11:58 +0200 Subject: [PATCH 07/16] fix: space --- Cargo.toml | 328 ++++++++++++++++++++++++++--------------------------- 1 file changed, 164 insertions(+), 164 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7ca5a03308..d8582c989fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,138 +47,138 @@ feat_acl = ["cp/feat_acl"] # * 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", - "ls/selinux", - "mkdir/selinux", - "mkfifo/selinux", - "mknod/selinux", - "stat/selinux", - "selinux", - "feat_require_selinux", + "cp/selinux", + "id/selinux", + "ls/selinux", + "mkdir/selinux", + "mkfifo/selinux", + "mknod/selinux", + "stat/selinux", + "selinux", + "feat_require_selinux", ] ## ## feature sets ## (common/core and Tier1) feature sets # "feat_common_core" == baseline core set of utilities which can be built/run on most targets feat_common_core = [ - "base32", - "base64", - "basename", - "basenc", - "cat", - "cksum", - "comm", - "cp", - "csplit", - "cut", - "date", - "df", - "dir", - "dircolors", - "dirname", - "dd", - "du", - "echo", - "env", - "expand", - "expr", - "factor", - "false", - "fmt", - "fold", - "hashsum", - "head", - "join", - "link", - "ln", - "ls", - "mkdir", - "mktemp", - "more", - "mv", - "nl", - "numfmt", - "od", - "paste", - "pr", - "printenv", - "printf", - "ptx", - "pwd", - "readlink", - "realpath", - "rm", - "rmdir", - "seq", - "shred", - "shuf", - "sleep", - "sort", - "split", - "sum", - "tac", - "tail", - "tee", - "test", - "tr", - "true", - "truncate", - "tsort", - "touch", - "unexpand", - "uniq", - "unlink", - "vdir", - "wc", - "yes", + "base32", + "base64", + "basename", + "basenc", + "cat", + "cksum", + "comm", + "cp", + "csplit", + "cut", + "date", + "df", + "dir", + "dircolors", + "dirname", + "dd", + "du", + "echo", + "env", + "expand", + "expr", + "factor", + "false", + "fmt", + "fold", + "hashsum", + "head", + "join", + "link", + "ln", + "ls", + "mkdir", + "mktemp", + "more", + "mv", + "nl", + "numfmt", + "od", + "paste", + "pr", + "printenv", + "printf", + "ptx", + "pwd", + "readlink", + "realpath", + "rm", + "rmdir", + "seq", + "shred", + "shuf", + "sleep", + "sort", + "split", + "sum", + "tac", + "tail", + "tee", + "test", + "tr", + "true", + "truncate", + "tsort", + "touch", + "unexpand", + "uniq", + "unlink", + "vdir", + "wc", + "yes", ] # "feat_Tier1" == expanded set of utilities which can be built/run on the usual rust "Tier 1" target platforms (ref: ) feat_Tier1 = [ - "feat_common_core", - # - "arch", - "hostname", - "nproc", - "sync", - "touch", - "uname", - "whoami", + "feat_common_core", + # + "arch", + "hostname", + "nproc", + "sync", + "touch", + "uname", + "whoami", ] ## (primary platforms) feature sets # "feat_os_macos" == set of utilities which can be built/run on the MacOS platform feat_os_macos = [ - "feat_os_unix", ## == a modern/usual *nix platform - # - "feat_require_unix_hostid", + "feat_os_unix", ## == a modern/usual *nix platform + # + "feat_require_unix_hostid", ] # "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms. # Also used for targets binding to the "musl" library (ref: ) feat_os_unix = [ - "feat_Tier1", - # - "feat_require_crate_cpp", - "feat_require_unix", - "feat_require_unix_utmpx", - "feat_require_unix_hostid", + "feat_Tier1", + # + "feat_require_crate_cpp", + "feat_require_unix", + "feat_require_unix_utmpx", + "feat_require_unix_hostid", ] # "feat_os_windows" == set of utilities which can be built/run on modern/usual windows platforms feat_os_windows = [ - "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" + "feat_Tier1", ## == "feat_os_windows_legacy" + "hostname" ] ## (secondary platforms) feature sets # "feat_os_unix_gnueabihf" == set of utilities which can be built/run on the "arm-unknown-linux-gnueabihf" target (ARMv6 Linux [hardfloat]) feat_os_unix_gnueabihf = [ - "feat_Tier1", - # - "feat_require_unix", - "feat_require_unix_hostid", - "feat_require_unix_utmpx", + "feat_Tier1", + # + "feat_require_unix", + "feat_require_unix_hostid", + "feat_require_unix_utmpx", ] feat_os_unix_android = [ - "feat_Tier1", - # - "feat_require_unix", + "feat_Tier1", + # + "feat_require_unix", ] ## feature sets with requirements (restricting cross-platform availability) # @@ -188,24 +188,24 @@ feat_os_unix_android = [ feat_require_crate_cpp = ["stdbuf"] # "feat_require_unix" == set of utilities requiring support which is only available on unix platforms (as of 2020-04-23) feat_require_unix = [ - "chgrp", - "chmod", - "chown", - "chroot", - "groups", - "id", - "install", - "kill", - "logname", - "mkfifo", - "mknod", - "nice", - "nohup", - "pathchk", - "stat", - "stty", - "timeout", - "tty", + "chgrp", + "chmod", + "chown", + "chroot", + "groups", + "id", + "install", + "kill", + "logname", + "mkfifo", + "mknod", + "nice", + "nohup", + "pathchk", + "stat", + "stty", + "timeout", + "tty", ] # "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support # * ref: @@ -217,43 +217,43 @@ feat_require_selinux = ["chcon", "runcon"] ## (alternate/newer/smaller platforms) feature sets # "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: ; ) feat_os_unix_fuchsia = [ - "feat_common_core", - # - "feat_require_crate_cpp", - # - "chgrp", - "chmod", - "chown", - "du", - "groups", - "hostid", - "install", - "logname", - "mkfifo", - "mknod", - "nice", - "pathchk", - "tty", - "uname", - "unlink", + "feat_common_core", + # + "feat_require_crate_cpp", + # + "chgrp", + "chmod", + "chown", + "du", + "groups", + "hostid", + "install", + "logname", + "mkfifo", + "mknod", + "nice", + "pathchk", + "tty", + "uname", + "unlink", ] # "feat_os_unix_redox" == set of utilities which can be built/run on "Redox OS" (refs: ; ) feat_os_unix_redox = [ - "feat_common_core", - # - "chmod", - "stat", - "uname", + "feat_common_core", + # + "chmod", + "stat", + "uname", ] # "feat_os_windows_legacy" == slightly restricted set of utilities which can be built/run on early windows platforms (eg, "WinXP") feat_os_windows_legacy = [ - "feat_common_core", - # - "arch", - "nproc", - "sync", - "touch", - "whoami", + "feat_common_core", + # + "arch", + "nproc", + "sync", + "touch", + "whoami", ] ## # * bypass/override ~ translate 'test' feature name to avoid dependency collision with rust core 'test' crate (o/w surfaces as compiler errors during testing) @@ -277,9 +277,9 @@ bstr = "1.9.1" bytecount = "0.6.8" byteorder = "1.5.0" chrono = { version = "0.4.38", default-features = false, features = [ - "std", - "alloc", - "clock", + "std", + "alloc", + "clock", ] } chrono-tz = "0.10.0" clap = { version = "4.5", features = ["wrap_help", "cargo"] } @@ -306,7 +306,7 @@ itertools = "0.14.0" libc = "0.2.172" linux-raw-sys = "0.9" lscolors = { version = "0.20.0", default-features = false, features = [ - "gnu_legacy", + "gnu_legacy", ] } memchr = "2.7.2" memmap2 = "0.9.4" @@ -509,11 +509,11 @@ time = { workspace = true, features = ["local-offset"] } unindent = "0.2.3" uutests = { workspace = true } uucore = { workspace = true, features = [ - "mode", - "entries", - "process", - "signals", - "utmpx", + "mode", + "entries", + "process", + "signals", + "utmpx", ] } walkdir = { workspace = true } hex-literal = "1.0.0" From c65845e9fe2ecf138ccaebd81a3657caf5d47dce Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 22:51:28 +0200 Subject: [PATCH 08/16] fix features flag --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d8582c989fb..427b8995093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core", "zip"] +default = ["feat_common_core", "dep:zip"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -35,7 +35,7 @@ expensive_tests = [] # "test_risky_names" == enable tests that create problematic file names (would make a network share inaccessible to Windows, breaks SVN on Mac OS, etc.) test_risky_names = [] # * only build `uudoc` when `--feature uudoc` is activated -uudoc = ["zip", "dep:uuhelp_parser"] +uudoc = ["dep:zip", "dep:uuhelp_parser"] ## features # "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) # NOTE: @@ -542,6 +542,7 @@ phf_codegen = { workspace = true } [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" +required-features = ["default"] [[bin]] name = "uudoc" From 7b75db17d9e26d4976d6640a50bf4bb4ded6af5e Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 23:00:47 +0200 Subject: [PATCH 09/16] change required feature --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 427b8995093..6125ea8423b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core", "dep:zip"] +default = ["feat_common_core"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -36,6 +36,7 @@ expensive_tests = [] test_risky_names = [] # * only build `uudoc` when `--feature uudoc` is activated uudoc = ["dep:zip", "dep:uuhelp_parser"] +coreutils = ["dep:zip"] ## features # "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) # NOTE: @@ -542,7 +543,7 @@ phf_codegen = { workspace = true } [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" -required-features = ["default"] +required-features = ["coreutils"] [[bin]] name = "uudoc" From 5e18f676faff86f82b3c42536fe4284af58c9249 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Fri, 25 Apr 2025 23:07:19 +0200 Subject: [PATCH 10/16] depencies --- Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6125ea8423b..427b8995093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core"] +default = ["feat_common_core", "dep:zip"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -36,7 +36,6 @@ expensive_tests = [] test_risky_names = [] # * only build `uudoc` when `--feature uudoc` is activated uudoc = ["dep:zip", "dep:uuhelp_parser"] -coreutils = ["dep:zip"] ## features # "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) # NOTE: @@ -543,7 +542,7 @@ phf_codegen = { workspace = true } [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" -required-features = ["coreutils"] +required-features = ["default"] [[bin]] name = "uudoc" From 0b2a48bf9699b59992d445fbe6a8f34a9ce4e077 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Tue, 6 May 2025 21:04:11 -0500 Subject: [PATCH 11/16] update --- Cargo.toml | 5 +++-- GNUmakefile | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 427b8995093..ee10e41b38d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ edition.workspace = true all-features = true [features] -default = ["feat_common_core", "dep:zip"] +default = ["feat_common_core", "coreutils"] ## OS feature shortcodes macos = ["feat_os_macos"] unix = ["feat_os_unix"] @@ -36,6 +36,7 @@ expensive_tests = [] test_risky_names = [] # * only build `uudoc` when `--feature uudoc` is activated uudoc = ["dep:zip", "dep:uuhelp_parser"] +coreutils = ["dep:zip"] ## features # "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) # NOTE: @@ -542,7 +543,7 @@ phf_codegen = { workspace = true } [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" -required-features = ["default"] +required-features = ["coreutils"] [[bin]] name = "uudoc" diff --git a/GNUmakefile b/GNUmakefile index 8d7179b5eb8..899bc07e24d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -300,7 +300,7 @@ endif endif build-coreutils: - ${CARGO} build ${CARGOFLAGS} --features "${EXES} $(BUILD_SPEC_FEATURE)" ${PROFILE_CMD} --no-default-features + ${CARGO} build ${CARGOFLAGS} --features "${EXES} $(BUILD_SPEC_FEATURE) coreutils" ${PROFILE_CMD} --no-default-features build: build-coreutils build-pkgs From 5a1f64beb69dcdaaa4e9bea3ad9f8f3e2d109376 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Tue, 6 May 2025 21:07:56 -0500 Subject: [PATCH 12/16] fix build.rs --- build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 3b6aa3878d1..7467b428feb 100644 --- a/build.rs +++ b/build.rs @@ -36,8 +36,9 @@ pub fn main() { "nightly" | "test_unimplemented" | "expensive_tests" | "test_risky_names" => { continue; } // crate-local custom features - "uudoc" => continue, // is not a utility + "uudoc" => continue, // is not a utility "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test' + "coreutils" => continue, // coreutils s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets _ => {} // util feature name } From 085f00a9526cb582082efd0868cd12e81d57a255 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Tue, 6 May 2025 21:21:08 -0500 Subject: [PATCH 13/16] fix ci --- .github/workflows/CICD.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index df1fba73c54..6bb5c088da4 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -1160,8 +1160,8 @@ jobs: run: | for f in $(util/show-utils.sh) do - echo "Running tests with --features=$f and --no-default-features" - cargo test --features=$f --no-default-features + echo "Running tests with --features="$f coreutils" --no-default-features" + cargo test --features="$f coreutils" --no-default-features done test_selinux: From c9bc1c7776db9f05a97bff411a73eb9daba49ed7 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Tue, 6 May 2025 21:22:55 -0500 Subject: [PATCH 14/16] fix not default features --- GNUmakefile | 4 ++-- src/uu/rm/benchmark.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 899bc07e24d..907211e17b4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -307,10 +307,10 @@ build: build-coreutils build-pkgs $(foreach test,$(filter-out $(SKIP_UTILS),$(PROGS)),$(eval $(call TEST_BUSYBOX,$(test)))) test: - ${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST) + ${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE) coreutils" --no-default-features $(TEST_NO_FAIL_FAST) nextest: - ${CARGO} nextest run ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST) + ${CARGO} nextest run ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE) coreutils" --no-default-features $(TEST_NO_FAIL_FAST) test_toybox: -(cd $(TOYBOX_SRC)/ && make tests) diff --git a/src/uu/rm/benchmark.sh b/src/uu/rm/benchmark.sh index 5feaea4e8f1..93d4d0b5466 100755 --- a/src/uu/rm/benchmark.sh +++ b/src/uu/rm/benchmark.sh @@ -3,6 +3,6 @@ # Exit on any failures set +x -cargo build --no-default-features --features rm --release +cargo build --no-default-features --features rm coreutils --release test_dir="$1" -hyperfine --prepare "cp -r $test_dir tmp_d" "rm -rf tmp_d" "target/release/coreutils rm -rf tmp_d" +hyperfine --prepare "cp -r $test_dir tmp_d" "rm -rf tmp_d" "target/release/coreutils rm -rf tmp_d" From afe66ff7903ee8836dcad1bf7c82512b4c08f1cf Mon Sep 17 00:00:00 2001 From: n4n5 Date: Tue, 6 May 2025 21:24:11 -0500 Subject: [PATCH 15/16] fix spaces --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 7467b428feb..b9be1d1e85b 100644 --- a/build.rs +++ b/build.rs @@ -36,7 +36,7 @@ pub fn main() { "nightly" | "test_unimplemented" | "expensive_tests" | "test_risky_names" => { continue; } // crate-local custom features - "uudoc" => continue, // is not a utility + "uudoc" => continue, // is not a utility "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test' "coreutils" => continue, // coreutils s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets From c163fc47e6a5a863877db92addd1dde3dc64a0c2 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Tue, 6 May 2025 21:32:54 -0500 Subject: [PATCH 16/16] cargo fmt --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index b9be1d1e85b..7467b428feb 100644 --- a/build.rs +++ b/build.rs @@ -36,7 +36,7 @@ pub fn main() { "nightly" | "test_unimplemented" | "expensive_tests" | "test_risky_names" => { continue; } // crate-local custom features - "uudoc" => continue, // is not a utility + "uudoc" => continue, // is not a utility "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test' "coreutils" => continue, // coreutils s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets