mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 11:07:44 +00:00
docs: show platforms for each util
This commit is contained in:
parent
5a3434161d
commit
3c09c747dd
2 changed files with 221 additions and 132 deletions
11
docs/theme/head.hbs
vendored
11
docs/theme/head.hbs
vendored
|
@ -5,10 +5,17 @@
|
|||
main {
|
||||
position: relative;
|
||||
}
|
||||
.version {
|
||||
.additional {
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
top: 0em;
|
||||
right: 0;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.platforms {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
dd > p {
|
||||
margin-top: 0.2em;
|
||||
|
|
342
src/bin/uudoc.rs
342
src/bin/uudoc.rs
|
@ -5,6 +5,7 @@
|
|||
// spell-checker:ignore tldr
|
||||
|
||||
use clap::Command;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io::Cursor;
|
||||
|
@ -29,6 +30,7 @@ fn main() -> io::Result<()> {
|
|||
x => x,
|
||||
}?;
|
||||
|
||||
println!("Writing initial info to SUMMARY.md");
|
||||
let mut summary = File::create("docs/src/SUMMARY.md")?;
|
||||
|
||||
let _ = write!(
|
||||
|
@ -44,6 +46,40 @@ fn main() -> io::Result<()> {
|
|||
* [Multi-call binary](multicall.md)\n",
|
||||
);
|
||||
|
||||
println!("Gathering utils per platform");
|
||||
let utils_per_platform = {
|
||||
let mut map = HashMap::new();
|
||||
for platform in ["unix", "macos", "windows"] {
|
||||
let platform_utils: Vec<String> = String::from_utf8(
|
||||
std::process::Command::new("./util/show-utils.sh")
|
||||
.arg(format!("--features=feat_os_{}", platform))
|
||||
.output()?
|
||||
.stdout,
|
||||
)
|
||||
.unwrap()
|
||||
.split(' ')
|
||||
.map(ToString::to_string)
|
||||
.collect();
|
||||
map.insert(platform, platform_utils);
|
||||
}
|
||||
|
||||
// Linux is a special case because it can support selinux
|
||||
let platform_utils: Vec<String> = String::from_utf8(
|
||||
std::process::Command::new("./util/show-utils.sh")
|
||||
.arg("--features=feat_os_unix feat_selinux")
|
||||
.output()?
|
||||
.stdout,
|
||||
)
|
||||
.unwrap()
|
||||
.split(' ')
|
||||
.map(ToString::to_string)
|
||||
.collect();
|
||||
map.insert("linux", platform_utils);
|
||||
|
||||
map
|
||||
};
|
||||
|
||||
println!("Writing to utils");
|
||||
let mut utils = utils.entries().collect::<Vec<_>>();
|
||||
utils.sort();
|
||||
for (&name, (_, command)) in utils {
|
||||
|
@ -52,7 +88,14 @@ fn main() -> io::Result<()> {
|
|||
}
|
||||
let p = format!("docs/src/utils/{}.md", name);
|
||||
if let Ok(f) = File::create(&p) {
|
||||
write_markdown(f, &mut command(), name, &mut tldr_zip)?;
|
||||
MDWriter {
|
||||
w: Box::new(f),
|
||||
command: command(),
|
||||
name,
|
||||
tldr_zip: &mut tldr_zip,
|
||||
utils_per_platform: &utils_per_platform,
|
||||
}
|
||||
.markdown()?;
|
||||
println!("Wrote to '{}'", p);
|
||||
} else {
|
||||
println!("Error writing to {}", p);
|
||||
|
@ -62,88 +105,185 @@ fn main() -> io::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_markdown(
|
||||
mut w: impl Write,
|
||||
command: &mut Command,
|
||||
name: &str,
|
||||
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>,
|
||||
) -> io::Result<()> {
|
||||
write!(w, "# {}\n\n", name)?;
|
||||
write_version(&mut w, command)?;
|
||||
write_usage(&mut w, command, name)?;
|
||||
write_description(&mut w, command)?;
|
||||
write_options(&mut w, command)?;
|
||||
write_examples(&mut w, name, tldr_zip)
|
||||
struct MDWriter<'a, 'b> {
|
||||
w: Box<dyn Write>,
|
||||
command: Command<'a>,
|
||||
name: &'a str,
|
||||
tldr_zip: &'b mut ZipArchive<Cursor<Vec<u8>>>,
|
||||
utils_per_platform: &'b HashMap<&'b str, Vec<String>>,
|
||||
}
|
||||
|
||||
fn write_version(w: &mut impl Write, command: &Command) -> io::Result<()> {
|
||||
writeln!(
|
||||
w,
|
||||
"<div class=\"version\">version: {}</div>",
|
||||
command.render_version().split_once(' ').unwrap().1
|
||||
)
|
||||
}
|
||||
impl<'a, 'b> MDWriter<'a, 'b> {
|
||||
fn markdown(&mut self) -> io::Result<()> {
|
||||
write!(self.w, "# {}\n\n", self.name)?;
|
||||
self.additional()?;
|
||||
self.usage()?;
|
||||
self.description()?;
|
||||
self.options()?;
|
||||
self.examples()
|
||||
}
|
||||
|
||||
fn write_usage(w: &mut impl Write, command: &mut Command, name: &str) -> io::Result<()> {
|
||||
writeln!(w, "\n```")?;
|
||||
let mut usage: String = command
|
||||
.render_usage()
|
||||
.lines()
|
||||
.skip(1)
|
||||
.map(|l| l.trim())
|
||||
.filter(|l| !l.is_empty())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
usage = usage.replace(uucore::execution_phrase(), name);
|
||||
writeln!(w, "{}", usage)?;
|
||||
writeln!(w, "```")
|
||||
}
|
||||
fn additional(&mut self) -> io::Result<()> {
|
||||
writeln!(self.w, "<div class=\"additional\">")?;
|
||||
self.platforms()?;
|
||||
self.version()?;
|
||||
writeln!(self.w, "</div>")
|
||||
}
|
||||
|
||||
fn platforms(&mut self) -> io::Result<()> {
|
||||
writeln!(self.w, "<div class=\"platforms\">")?;
|
||||
for (feature, icon) in [
|
||||
("linux", "linux"),
|
||||
// freebsd is disabled for now because mdbook does not use font-awesome 5 yet.
|
||||
// ("unix", "freebsd"),
|
||||
("macos", "apple"),
|
||||
("windows", "windows"),
|
||||
] {
|
||||
if self.name.contains("sum")
|
||||
|| self.utils_per_platform[feature]
|
||||
.iter()
|
||||
.any(|u| u == self.name)
|
||||
{
|
||||
writeln!(self.w, "<i class=\"fa-brands fa-{}\"></i>", icon)?;
|
||||
}
|
||||
}
|
||||
writeln!(self.w, "</div>")?;
|
||||
|
||||
fn write_description(w: &mut impl Write, command: &Command) -> io::Result<()> {
|
||||
if let Some(about) = command.get_long_about().or_else(|| command.get_about()) {
|
||||
writeln!(w, "{}", about)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_examples(
|
||||
w: &mut impl Write,
|
||||
name: &str,
|
||||
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>,
|
||||
) -> io::Result<()> {
|
||||
let content = if let Some(f) = get_zip_content(tldr_zip, &format!("pages/common/{}.md", name)) {
|
||||
f
|
||||
} else if let Some(f) = get_zip_content(tldr_zip, &format!("pages/linux/{}.md", name)) {
|
||||
f
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
fn version(&mut self) -> io::Result<()> {
|
||||
writeln!(
|
||||
self.w,
|
||||
"<div class=\"version\">v{}</div>",
|
||||
self.command.render_version().split_once(' ').unwrap().1
|
||||
)
|
||||
}
|
||||
|
||||
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, "```shell\n{}\n```", line.trim_matches('`'))?;
|
||||
} else if line.is_empty() {
|
||||
writeln!(w)?;
|
||||
fn usage(&mut self) -> io::Result<()> {
|
||||
writeln!(self.w, "\n```")?;
|
||||
let mut usage: String = self
|
||||
.command
|
||||
.render_usage()
|
||||
.lines()
|
||||
.skip(1)
|
||||
.map(|l| l.trim())
|
||||
.filter(|l| !l.is_empty())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
usage = usage.replace(uucore::execution_phrase(), self.name);
|
||||
writeln!(self.w, "{}", usage)?;
|
||||
writeln!(self.w, "```")
|
||||
}
|
||||
|
||||
fn description(&mut self) -> io::Result<()> {
|
||||
if let Some(about) = self
|
||||
.command
|
||||
.get_long_about()
|
||||
.or_else(|| self.command.get_about())
|
||||
{
|
||||
writeln!(self.w, "{}", about)
|
||||
} else {
|
||||
println!("Not sure what to do with this line:");
|
||||
println!("{}", line);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
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, ">")?;
|
||||
writeln!(
|
||||
w,
|
||||
"> Please note that, as uutils is a work in progress, some examples might fail."
|
||||
)
|
||||
|
||||
fn examples(&mut self) -> io::Result<()> {
|
||||
let content = if let Some(f) =
|
||||
get_zip_content(self.tldr_zip, &format!("pages/common/{}.md", self.name))
|
||||
{
|
||||
f
|
||||
} else if let Some(f) =
|
||||
get_zip_content(self.tldr_zip, &format!("pages/linux/{}.md", self.name))
|
||||
{
|
||||
f
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
writeln!(self.w, "## Examples")?;
|
||||
writeln!(self.w)?;
|
||||
for line in content.lines().skip_while(|l| !l.starts_with('-')) {
|
||||
if let Some(l) = line.strip_prefix("- ") {
|
||||
writeln!(self.w, "{}", l)?;
|
||||
} else if line.starts_with('`') {
|
||||
writeln!(self.w, "```shell\n{}\n```", line.trim_matches('`'))?;
|
||||
} else if line.is_empty() {
|
||||
writeln!(self.w)?;
|
||||
} else {
|
||||
println!("Not sure what to do with this line:");
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
writeln!(self.w)?;
|
||||
writeln!(
|
||||
self.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!(self.w, ">")?;
|
||||
writeln!(
|
||||
self.w,
|
||||
"> Please note that, as uutils is a work in progress, some examples might fail."
|
||||
)
|
||||
}
|
||||
|
||||
fn options(&mut self) -> io::Result<()> {
|
||||
writeln!(self.w, "<h2>Options</h2>")?;
|
||||
write!(self.w, "<dl>")?;
|
||||
for arg in self.command.get_arguments() {
|
||||
write!(self.w, "<dt>")?;
|
||||
let mut first = true;
|
||||
for l in arg.get_long_and_visible_aliases().unwrap_or_default() {
|
||||
if !first {
|
||||
write!(self.w, ", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
write!(self.w, "<code>")?;
|
||||
write!(self.w, "--{}", l)?;
|
||||
if let Some(names) = arg.get_value_names() {
|
||||
write!(
|
||||
self.w,
|
||||
"={}",
|
||||
names
|
||||
.iter()
|
||||
.map(|x| format!("<{}>", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
)?;
|
||||
}
|
||||
write!(self.w, "</code>")?;
|
||||
}
|
||||
for s in arg.get_short_and_visible_aliases().unwrap_or_default() {
|
||||
if !first {
|
||||
write!(self.w, ", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
write!(self.w, "<code>")?;
|
||||
write!(self.w, "-{}", s)?;
|
||||
if let Some(names) = arg.get_value_names() {
|
||||
write!(
|
||||
self.w,
|
||||
" {}",
|
||||
names
|
||||
.iter()
|
||||
.map(|x| format!("<{}>", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
)?;
|
||||
}
|
||||
write!(self.w, "</code>")?;
|
||||
}
|
||||
writeln!(self.w, "</dt>")?;
|
||||
writeln!(
|
||||
self.w,
|
||||
"<dd>\n\n{}\n\n</dd>",
|
||||
arg.get_help().unwrap_or_default().replace('\n', "<br />")
|
||||
)?;
|
||||
}
|
||||
writeln!(self.w, "</dl>\n")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Option<String> {
|
||||
|
@ -151,61 +291,3 @@ fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Op
|
|||
archive.by_name(name).ok()?.read_to_string(&mut s).unwrap();
|
||||
Some(s)
|
||||
}
|
||||
|
||||
fn write_options(w: &mut impl Write, command: &Command) -> io::Result<()> {
|
||||
writeln!(w, "<h2>Options</h2>")?;
|
||||
write!(w, "<dl>")?;
|
||||
for arg in command.get_arguments() {
|
||||
write!(w, "<dt>")?;
|
||||
let mut first = true;
|
||||
for l in arg.get_long_and_visible_aliases().unwrap_or_default() {
|
||||
if !first {
|
||||
write!(w, ", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
write!(w, "<code>")?;
|
||||
write!(w, "--{}", l)?;
|
||||
if let Some(names) = arg.get_value_names() {
|
||||
write!(
|
||||
w,
|
||||
"={}",
|
||||
names
|
||||
.iter()
|
||||
.map(|x| format!("<{}>", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
)?;
|
||||
}
|
||||
write!(w, "</code>")?;
|
||||
}
|
||||
for s in arg.get_short_and_visible_aliases().unwrap_or_default() {
|
||||
if !first {
|
||||
write!(w, ", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
write!(w, "<code>")?;
|
||||
write!(w, "-{}", s)?;
|
||||
if let Some(names) = arg.get_value_names() {
|
||||
write!(
|
||||
w,
|
||||
" {}",
|
||||
names
|
||||
.iter()
|
||||
.map(|x| format!("<{}>", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
)?;
|
||||
}
|
||||
write!(w, "</code>")?;
|
||||
}
|
||||
writeln!(w, "</dt>")?;
|
||||
writeln!(
|
||||
w,
|
||||
"<dd>\n\n{}\n\n</dd>",
|
||||
arg.get_help().unwrap_or_default().replace('\n', "<br />")
|
||||
)?;
|
||||
}
|
||||
writeln!(w, "</dl>\n")
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue