Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/cspell.dictionaries/workspace.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ bytecount
byteorder
chacha
chrono
clap_mangen
conv
corasick
crossterm
Expand Down
5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,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 = ["zip", "dep:uuhelp_parser", "clap_mangen"]
## features
## Optional feature for stdbuf
# "feat_external_libstdbuf" == use an external libstdbuf.so for stdbuf instead of embedding it
Expand Down Expand Up @@ -295,7 +295,6 @@ chrono = { version = "0.4.41", default-features = false, features = [
] }
clap = { version = "4.5", features = ["wrap_help", "cargo"] }
clap_complete = "4.4"
clap_mangen = "0.2"
compare = "0.1.0"
crossterm = "0.29.0"
ctor = "0.4.1"
Expand Down Expand Up @@ -392,7 +391,7 @@ uutests = { version = "0.1.0", package = "uutests", path = "tests/uutests" }
clap.workspace = true
uucore.workspace = true
clap_complete.workspace = true
clap_mangen.workspace = true
clap_mangen = { version = "0.2", optional = true }
phf.workspace = true
selinux = { workspace = true, optional = true }
textwrap.workspace = true
Expand Down
11 changes: 7 additions & 4 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
PROFILE ?= debug
MULTICALL ?= n
COMPLETIONS ?= y
MANPAGES ?= y
MANPAGES ?= n
LOCALES ?= y
INSTALL ?= install
ifneq (,$(filter install, $(MAKECMDGOALS)))
Expand Down Expand Up @@ -379,10 +379,13 @@ distclean: clean
$(CARGO) clean $(CARGOFLAGS) && $(CARGO) update $(CARGOFLAGS)

ifeq ($(MANPAGES),y)
manpages: build-coreutils
build-uudoc:
${CARGO} build ${CARGOFLAGS} --features uudoc ${PROFILE_CMD}

manpages: build-coreutils build-uudoc
mkdir -p $(BUILDDIR)/man/
$(foreach prog, $(INSTALLEES), \
$(BUILDDIR)/coreutils manpage $(prog) > $(BUILDDIR)/man/$(PROG_PREFIX)$(prog).1 $(newline) \
$(BUILDDIR)/uudoc manpage $(prog) > $(BUILDDIR)/man/$(PROG_PREFIX)$(prog).1 $(newline) \
)

install-manpages: manpages
Expand Down Expand Up @@ -479,4 +482,4 @@ endif
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS)))
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/man/man1/$(PROG_PREFIX),$(addsuffix .1,$(PROGS)))

.PHONY: all build build-coreutils build-pkgs test distclean clean busytest install uninstall
.PHONY: all build build-coreutils build-pkgs build-uudoc test distclean clean busytest install uninstall
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ cargo run completion ls bash > /usr/local/share/bash-completion/completions/ls
To generate manpages, the syntax is:

```bash
cargo run manpage <utility>
cargo run --bin uudoc --features uudoc -- manpage <utility>
```

So, to install the manpage for `ls` to `/usr/local/share/man/man1/ls.1` run:

```bash
cargo run manpage ls > /usr/local/share/man/man1/ls.1
cargo run --bin uudoc --features uudoc -- manpage ls > /usr/local/share/man/man1/ls.1
```

## Un-installation
Expand Down
3 changes: 2 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ 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
"clap_mangen" => continue, // is not a utility
"test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test'
s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets
_ => {} // util feature name
Expand Down
37 changes: 0 additions & 37 deletions src/bin/coreutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ fn main() {

match util {
"completion" => gen_completions(args, &utils),
"manpage" => gen_manpage(args, &utils),
"--list" => {
let mut utils: Vec<_> = utils.keys().collect();
utils.sort();
Expand Down Expand Up @@ -239,42 +238,6 @@ fn gen_completions<T: uucore::Args>(
process::exit(0);
}

/// Generate the manpage for the utility in the first parameter
/// # Panics
/// Panics if the utility map is empty
fn gen_manpage<T: uucore::Args>(
args: impl Iterator<Item = OsString>,
util_map: &UtilityMap<T>,
) -> ! {
let all_utilities: Vec<_> = std::iter::once("coreutils")
.chain(util_map.keys().copied())
.collect();

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));

let utility = matches.get_one::<String>("utility").unwrap();

let command = if utility == "coreutils" {
gen_coreutils_app(util_map)
} else {
setup_localization_or_exit(utility);
util_map.get(utility).unwrap().1()
};

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
/// Panics if the utility map is empty
fn gen_coreutils_app<T: uucore::Args>(util_map: &UtilityMap<T>) -> Command {
Expand Down
75 changes: 74 additions & 1 deletion src/bin/uudoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,92 @@
// file that was distributed with this source code.
// spell-checker:ignore tldr uuhelp

use clap::Command;
use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::io::{self, Read, Seek, Write};

use clap::{Arg, Command};
use zip::ZipArchive;

include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));

#[cfg(feature = "uudoc")]
/// Generate the manpage for the utility in the first parameter
/// # Panics
/// Panics if the utility map is empty
fn gen_manpage<T: uucore::Args>(
args: impl Iterator<Item = OsString>,
util_map: &UtilityMap<T>,
) -> ! {
let all_utilities: Vec<_> = std::iter::once("coreutils")
.chain(util_map.keys().copied())
.collect();

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));

let utility = matches.get_one::<String>("utility").unwrap();

let command = if utility == "coreutils" {
gen_coreutils_app(util_map)
} else {
uucore::locale::setup_localization(utility).unwrap_or_else(|err| {
match err {
uucore::locale::LocalizationError::ParseResource {
error: err_msg,
snippet,
} => eprintln!("Localization parse error at {snippet}: {err_msg}"),
other => eprintln!("Could not init the localization system: {other}"),
}
std::process::exit(99)
});
util_map.get(utility).unwrap().1()
};

let man = clap_mangen::Man::new(command);
man.render(&mut io::stdout())
.expect("Man page generation failed");
io::stdout().flush().unwrap();
std::process::exit(0);
}

/// # Panics
/// Panics if the utility map is empty
fn gen_coreutils_app<T: uucore::Args>(util_map: &UtilityMap<T>) -> Command {
let mut command = Command::new("coreutils");
for (name, (_, sub_app)) in util_map {
// Recreate a small subcommand with only the relevant info
// (name & short description)
let about = sub_app()
.get_about()
.expect("Could not get the 'about'")
.to_string();
let sub_app = Command::new(name).about(about);
command = command.subcommand(sub_app);
}
command
}

/// # Errors
/// Returns an error if the writer fails.
#[allow(clippy::too_many_lines)]
fn main() -> io::Result<()> {
let args: Vec<OsString> = std::env::args_os().collect();

// Check if this is a manpage generation request
#[cfg(feature = "uudoc")]
if args.len() > 1 && args[1] == "manpage" {
let utils = util_map::<Box<dyn Iterator<Item = OsString>>>();
gen_manpage(args.into_iter().skip(2), &utils);
}

let mut tldr_zip = File::open("docs/tldr.zip")
.ok()
.and_then(|f| ZipArchive::new(f).ok());
Expand Down
40 changes: 0 additions & 40 deletions tests/by-util/test_base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use uutests::new_ucmd;
use uutests::util::TestScenario;

#[test]
fn test_encode() {
Expand Down Expand Up @@ -219,42 +218,3 @@ cyBvdmVyIHRoZSBsYXp5IGRvZy4=
// cSpell:enable
);
}

// Prevent regression to:
//
// ❯ coreutils manpage base64 | rg --fixed-strings -- 'base32'
// The data are encoded as described for the base32 alphabet in RFC 4648.
// to the bytes of the formal base32 alphabet. Use \-\-ignore\-garbage
// The data are encoded as described for the base32 alphabet in RFC 4648.
// to the bytes of the formal base32 alphabet. Use \-\-ignore\-garbage
#[test]
fn test_manpage() {
use std::process::{Command, Stdio};
unsafe {
// force locale to english to avoid issues with manpage output
std::env::set_var("LANG", "C");
}

let test_scenario = TestScenario::new("");

let child = Command::new(&test_scenario.bin_path)
.arg("manpage")
.arg("base64")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();

let output = child.wait_with_output().unwrap();

assert_eq!(output.status.code().unwrap(), 0);

assert!(output.stderr.is_empty());

let stdout_str = std::str::from_utf8(&output.stdout).unwrap();

assert!(stdout_str.contains("base64 alphabet"));

assert!(!stdout_str.to_ascii_lowercase().contains("base32"));
}
Loading
Loading