1
Fork 0
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:
Terts Diepraam 2022-04-07 15:12:21 +02:00
parent 5a3434161d
commit 3c09c747dd
2 changed files with 221 additions and 132 deletions

11
docs/theme/head.hbs vendored
View file

@ -5,10 +5,17 @@
main { main {
position: relative; position: relative;
} }
.version { .additional {
position: absolute; position: absolute;
top: 1em; top: 0em;
right: 0; right: 0;
display: flex;
gap: 5px;
align-items: center;
font-size: 1.3em;
}
.platforms {
font-size: 1.5em;
} }
dd > p { dd > p {
margin-top: 0.2em; margin-top: 0.2em;

View file

@ -5,6 +5,7 @@
// spell-checker:ignore tldr // spell-checker:ignore tldr
use clap::Command; use clap::Command;
use std::collections::HashMap;
use std::ffi::OsString; use std::ffi::OsString;
use std::fs::File; use std::fs::File;
use std::io::Cursor; use std::io::Cursor;
@ -29,6 +30,7 @@ fn main() -> io::Result<()> {
x => x, x => x,
}?; }?;
println!("Writing initial info to SUMMARY.md");
let mut summary = File::create("docs/src/SUMMARY.md")?; let mut summary = File::create("docs/src/SUMMARY.md")?;
let _ = write!( let _ = write!(
@ -44,6 +46,40 @@ fn main() -> io::Result<()> {
* [Multi-call binary](multicall.md)\n", * [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<_>>(); let mut utils = utils.entries().collect::<Vec<_>>();
utils.sort(); utils.sort();
for (&name, (_, command)) in utils { for (&name, (_, command)) in utils {
@ -52,7 +88,14 @@ fn main() -> io::Result<()> {
} }
let p = format!("docs/src/utils/{}.md", name); let p = format!("docs/src/utils/{}.md", name);
if let Ok(f) = File::create(&p) { 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); println!("Wrote to '{}'", p);
} else { } else {
println!("Error writing to {}", p); println!("Error writing to {}", p);
@ -62,88 +105,185 @@ fn main() -> io::Result<()> {
Ok(()) Ok(())
} }
fn write_markdown( struct MDWriter<'a, 'b> {
mut w: impl Write, w: Box<dyn Write>,
command: &mut Command, command: Command<'a>,
name: &str, name: &'a str,
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>, tldr_zip: &'b mut ZipArchive<Cursor<Vec<u8>>>,
) -> io::Result<()> { utils_per_platform: &'b HashMap<&'b str, Vec<String>>,
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)
} }
fn write_version(w: &mut impl Write, command: &Command) -> io::Result<()> { impl<'a, 'b> MDWriter<'a, 'b> {
writeln!( fn markdown(&mut self) -> io::Result<()> {
w, write!(self.w, "# {}\n\n", self.name)?;
"<div class=\"version\">version: {}</div>", self.additional()?;
command.render_version().split_once(' ').unwrap().1 self.usage()?;
) self.description()?;
} self.options()?;
self.examples()
}
fn write_usage(w: &mut impl Write, command: &mut Command, name: &str) -> io::Result<()> { fn additional(&mut self) -> io::Result<()> {
writeln!(w, "\n```")?; writeln!(self.w, "<div class=\"additional\">")?;
let mut usage: String = command self.platforms()?;
.render_usage() self.version()?;
.lines() writeln!(self.w, "</div>")
.skip(1) }
.map(|l| l.trim())
.filter(|l| !l.is_empty()) fn platforms(&mut self) -> io::Result<()> {
.collect::<Vec<_>>() writeln!(self.w, "<div class=\"platforms\">")?;
.join("\n"); for (feature, icon) in [
usage = usage.replace(uucore::execution_phrase(), name); ("linux", "linux"),
writeln!(w, "{}", usage)?; // freebsd is disabled for now because mdbook does not use font-awesome 5 yet.
writeln!(w, "```") // ("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(()) Ok(())
} }
}
fn write_examples( fn version(&mut self) -> io::Result<()> {
w: &mut impl Write, writeln!(
name: &str, self.w,
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>, "<div class=\"version\">v{}</div>",
) -> io::Result<()> { self.command.render_version().split_once(' ').unwrap().1
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(());
};
writeln!(w, "## Examples")?; fn usage(&mut self) -> io::Result<()> {
writeln!(w)?; writeln!(self.w, "\n```")?;
for line in content.lines().skip_while(|l| !l.starts_with('-')) { let mut usage: String = self
if let Some(l) = line.strip_prefix("- ") { .command
writeln!(w, "{}", l)?; .render_usage()
} else if line.starts_with('`') { .lines()
writeln!(w, "```shell\n{}\n```", line.trim_matches('`'))?; .skip(1)
} else if line.is_empty() { .map(|l| l.trim())
writeln!(w)?; .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 { } else {
println!("Not sure what to do with this line:"); Ok(())
println!("{}", line);
} }
} }
writeln!(w)?;
writeln!( fn examples(&mut self) -> io::Result<()> {
w, let content = if let Some(f) =
"> 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)." get_zip_content(self.tldr_zip, &format!("pages/common/{}.md", self.name))
)?; {
writeln!(w, ">")?; f
writeln!( } else if let Some(f) =
w, get_zip_content(self.tldr_zip, &format!("pages/linux/{}.md", self.name))
"> Please note that, as uutils is a work in progress, some examples might fail." {
) 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!("&lt;{}&gt;", 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!("&lt;{}&gt;", 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> { 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(); archive.by_name(name).ok()?.read_to_string(&mut s).unwrap();
Some(s) 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!("&lt;{}&gt;", 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!("&lt;{}&gt;", 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")
}