use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use anyhow::Context;
pub mod man;
type Result<T, E=anyhow::Error> = std::result::Result<T, E>;
pub const ASSET_OUT_DIR: &str = "ASSET_OUT_DIR";
pub fn asset_out_dir(asset: &str) -> Result<PathBuf> {
println!("cargo:rerun-if-env-changed={}", ASSET_OUT_DIR);
let outdir: PathBuf =
env::var_os(ASSET_OUT_DIR).unwrap_or_else(
|| env::var_os("OUT_DIR").expect("OUT_DIR not set")).into();
if outdir.exists() && ! outdir.is_dir() {
return Err(anyhow::anyhow!("{}={:?} is not a directory",
ASSET_OUT_DIR, outdir));
}
let path = outdir.join(asset);
fs::create_dir_all(&path)?;
Ok(path)
}
pub const MAN_PANDOC_LUA: &[u8] = include_bytes!("man-pandoc.lua");
pub const MAN_PANDOC_INC_HTML: &[u8] = include_bytes!("man-pandoc.inc.html");
pub fn generate_man_pages(asset_dir: &Path, builder: &man::Builder)
-> Result<()>
{
let mut man2html = String::new();
man2html.push_str("#! /bin/bash\n");
man2html.push_str("# Convert the man pages to HTML using pandoc.\n");
man2html.push_str("\n");
man2html.push_str("set -e\n\n");
man2html.push_str("cd $(dirname $0)\n\n");
man2html.push_str("FILES=\"");
for man in builder.build() {
man2html.push_str(&format!(" {}", man.filename().display()));
std::fs::write(asset_dir.join(man.filename()), man.troff_source())?;
}
man2html.push_str("\"\n");
man2html.push_str("\n");
man2html.push_str(&format!("\
case \"$1\" in
--generate)
for man_page in $FILES
do
BINARY={} pandoc -s $man_page -L man-pandoc.lua -H man-pandoc.inc.html -o $man_page.html
done
;;
--man-files)
for man_page in $FILES
do
echo $man_page
done
;;
--man-root)
for man_page in $FILES
do
echo $man_page
break
done
;;
--html-files)
for man_page in $FILES
do
echo $man_page.html
done
;;
--html-root)
for man_page in $FILES
do
echo $man_page.html
break
done
;;
*)
echo \"Usage: $0 --generate|--man-files|--man-root|--html-files|--html-root\"
exit 1
;;
esac
", builder.binary()));
let target = asset_dir.join("man-pandoc.lua");
std::fs::write(&target, MAN_PANDOC_LUA)
.with_context(|| format!("Writing {}", target.display()))?;
let target = asset_dir.join("man-pandoc.inc.html");
std::fs::write(&target, MAN_PANDOC_INC_HTML)
.with_context(|| format!("Writing {}", target.display()))?;
let target = asset_dir.join("man2html.sh");
let mut f = std::fs::File::create(&target)
.with_context(|| format!("Crating {}", target.display()))?;
f.write_all(man2html.as_bytes())?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let metadata = f.metadata()?;
let mut permissions = metadata.permissions();
permissions.set_mode(permissions.mode() | 0o100);
f.set_permissions(permissions)?;
}
println!("cargo:warning=man pages written to {}", asset_dir.display());
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use clap::CommandFactory;
use clap::Parser;
#[derive(Parser, Debug)]
#[clap(
name = "frob",
about = "A tool to help with frobnication.")]
struct Cli {
#[arg(long="intensity")]
intensity: usize,
}
#[test]
fn build() {
let dir = tempfile::TempDir::new().unwrap();
let mut cli = Cli::command();
let mut builder = man::Builder::new(
&mut cli, env!("CARGO_PKG_VERSION"), None);
builder.see_also(&[ "For the full documentation see <https://...>." ]);
generate_man_pages(dir.path(), &builder).unwrap();
if false {
let p = dir.into_path();
eprintln!("Persisted output to: {}", p.display());
}
}
}