mirror of
https://github.com/rust-vmm/vhost-device.git
synced 2026-01-08 20:57:35 +00:00
xtask: also generate EXAMPLES section
Include "Examples" section from READMEs if they exist into the generated manual page. Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
This commit is contained in:
parent
72f811cf4f
commit
f6f4a90e12
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -857,6 +857,15 @@ version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "1.0.0-alpha.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9047e0a37a596d4e15411a1ffbdabe71c328908cb90a721cb9bf8dcf3434e6d2"
|
||||
dependencies = [
|
||||
"unicode-id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@ -1741,6 +1750,12 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-id"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
@ -2350,6 +2365,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_mangen",
|
||||
"markdown",
|
||||
"toml 0.8.19",
|
||||
]
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ publish = false
|
||||
clap = { version = "4.5", features = ["derive"], optional = true }
|
||||
clap_mangen = { version = "0.2.24", optional = true }
|
||||
toml = { version = "0.8.19", optional = true }
|
||||
markdown = { version = "=1.0.0-alpha.23", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@ -22,7 +23,7 @@ vhost-device-scmi = []
|
||||
vhost-device-sound = ["vhost-device-sound-alsa", "vhost-device-sound-pipewire"]
|
||||
vhost-device-sound-alsa = ["mangen"]
|
||||
vhost-device-sound-pipewire = ["mangen"]
|
||||
mangen = ["dep:clap_mangen", "dep:clap", "dep:toml"]
|
||||
mangen = ["dep:clap_mangen", "dep:clap", "dep:toml", "dep:markdown"]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(feature, values("alsa-backend", "pw-backend"))'] }
|
||||
|
||||
@ -6,6 +6,8 @@ This binary crate provides support for running useful tasks with `cargo xtask <.
|
||||
|
||||
The `mangen` task which is enabled by the `mangen` cargo feature, builds ROFF manual pages for binary crates in this repository. It uses the [`clap_mangen`](https://crates.io/crates/clap_mangen) crate to generate ROFF from the crate's argument types which implement the `clap::CommandFactory` trait, through the `clap::Parser` derive macro.
|
||||
|
||||
Furthmore, if the `README.md` of a crate contains an `Examples` heading, it includes it in the manual page.
|
||||
|
||||
```session
|
||||
$ cargo xtask mangen
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
|
||||
|
||||
@ -15,6 +15,8 @@ use clap::CommandFactory;
|
||||
#[cfg(feature = "mangen")]
|
||||
use clap_mangen::Man;
|
||||
#[cfg(feature = "mangen")]
|
||||
use markdown::{to_mdast, ParseOptions};
|
||||
#[cfg(feature = "mangen")]
|
||||
use toml::value::Table;
|
||||
|
||||
// Use vhost-device-sound's args module as our own using the #[path] attribute
|
||||
@ -63,7 +65,19 @@ fn print_help() {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mangen")]
|
||||
fn mangen_for_crate<T: CommandFactory>(manifest: Table) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
fn mangen_for_crate<T: CommandFactory>(
|
||||
crate_dir: std::path::PathBuf,
|
||||
) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let readme_md = std::fs::read_to_string(crate_dir.join("README.md"))?;
|
||||
let example_text = parse_examples_from_readme(readme_md).unwrap_or_default();
|
||||
let examples = if example_text.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(example_text.trim())
|
||||
};
|
||||
let manifest = std::fs::read_to_string(crate_dir.join("Cargo.toml"))?;
|
||||
let manifest = manifest.as_str().parse::<Table>()?;
|
||||
|
||||
let name: &'static str = manifest["package"]["name"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
@ -94,6 +108,14 @@ fn mangen_for_crate<T: CommandFactory>(manifest: Table) -> Result<Vec<u8>, Box<d
|
||||
let man = Man::new(cmd);
|
||||
let mut buffer: Vec<u8> = Default::default();
|
||||
man.render(&mut buffer)?;
|
||||
if let Some(examples) = examples {
|
||||
let mut examples_section = clap_mangen::roff::Roff::new();
|
||||
examples_section.control("SH", ["EXAMPLES"]);
|
||||
for line in examples.lines() {
|
||||
examples_section.text(vec![line.into()]);
|
||||
}
|
||||
examples_section.to_writer(&mut buffer)?;
|
||||
}
|
||||
clap_mangen::roff::Roff::new()
|
||||
.control("SH", ["REPORTING BUGS"])
|
||||
.text(vec![format!(
|
||||
@ -105,6 +127,41 @@ fn mangen_for_crate<T: CommandFactory>(manifest: Table) -> Result<Vec<u8>, Box<d
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "mangen")]
|
||||
fn parse_examples_from_readme(readme_md: String) -> Result<String, Box<dyn Error>> {
|
||||
use markdown::mdast;
|
||||
|
||||
let mdast = to_mdast(&readme_md, &ParseOptions::gfm()).map_err(|err| err.to_string())?;
|
||||
let mut example_text = String::new();
|
||||
if let mdast::Node::Root(root) = mdast {
|
||||
if let Some(examples_index) = root.children.iter().position(|r| matches!(r, mdast::Node::Heading(mdast::Heading { ref children, .. }) if matches!(children.first(), Some(mdast::Node::Text(mdast::Text { ref value, .. })) if value.trim() == "Examples"))){
|
||||
let mdast::Node::Heading(examples_heading) =
|
||||
&root.children[examples_index]
|
||||
else {
|
||||
// SAFETY: Unreachable because we found the exact position earlier.
|
||||
unreachable!();
|
||||
};
|
||||
let depth = examples_heading.depth;
|
||||
let mut i = examples_index + 1;
|
||||
while i < root.children.len() && !matches!(root.children[i], mdast::Node::Heading(ref h) if h.depth >= depth) {
|
||||
match &root.children[i] {
|
||||
mdast::Node::Paragraph(p) => {
|
||||
example_text.push_str(&p.children.iter().map(|t| t.to_string()).collect::<Vec<String>>().join(" "));
|
||||
example_text.push_str("\n\n");
|
||||
},
|
||||
mdast::Node::Code(c) => {
|
||||
example_text.push_str(&c.value);
|
||||
example_text.push_str("\n\n");
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(example_text)
|
||||
}
|
||||
|
||||
#[cfg(feature = "mangen")]
|
||||
fn mangen() -> Result<(), Box<dyn Error>> {
|
||||
let workspace_dir = std::path::Path::new(&env!("CARGO_MANIFEST_DIR"))
|
||||
@ -124,11 +181,7 @@ fn mangen() -> Result<(), Box<dyn Error>> {
|
||||
{
|
||||
use vhost_device_sound::SoundArgs;
|
||||
|
||||
let manifest =
|
||||
std::fs::read_to_string(workspace_dir.join("vhost-device-sound/Cargo.toml"))?;
|
||||
let manifest = manifest.as_str().parse::<Table>()?;
|
||||
|
||||
let buffer = mangen_for_crate::<SoundArgs>(manifest)?;
|
||||
let buffer = mangen_for_crate::<SoundArgs>(workspace_dir.join("vhost-device-sound"))?;
|
||||
let man_path = dist_dir.join("vhost-device-sound.1");
|
||||
buffers.push((man_path, buffer));
|
||||
}
|
||||
@ -136,10 +189,7 @@ fn mangen() -> Result<(), Box<dyn Error>> {
|
||||
{
|
||||
use vhost_device_scmi::ScmiArgs;
|
||||
|
||||
let manifest = std::fs::read_to_string(workspace_dir.join("vhost-device-scmi/Cargo.toml"))?;
|
||||
let manifest = manifest.as_str().parse::<Table>()?;
|
||||
|
||||
let buffer = mangen_for_crate::<ScmiArgs>(manifest)?;
|
||||
let buffer = mangen_for_crate::<ScmiArgs>(workspace_dir.join("vhost-device-scmi"))?;
|
||||
let man_path = dist_dir.join("vhost-device-scmi.1");
|
||||
buffers.push((man_path, buffer));
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user