Skip to content

Commit

Permalink
rage: Build manpages in the build script
Browse files Browse the repository at this point in the history
  • Loading branch information
str4d committed Jan 11, 2024
1 parent 0a6cb79 commit 91a5818
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 274 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,6 @@ jobs:
run: cargo build --release --locked --target ${{ matrix.target }} ${{ matrix.build_flags }}
working-directory: ./rage

- name: Generate manpages
run: cargo run --example generate-docs

- name: Update Debian package config for cross-compile
run: sed -i '/\/rage-mount/d' rage/Cargo.toml
if: matrix.name != 'linux'
Expand Down
25 changes: 13 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions rage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ assets = [
["target/release/completions/_rage", "usr/share/zsh/functions/Completion/Debian/", "644"],
["target/release/completions/_rage-keygen", "usr/share/zsh/functions/Completion/Debian/", "644"],
["target/release/completions/_rage-mount", "usr/share/zsh/functions/Completion/Debian/", "644"],
["../target/manpages/rage.1.gz", "usr/share/man/man1/", "644"],
["../target/manpages/rage-keygen.1.gz", "usr/share/man/man1/", "644"],
["../target/manpages/rage-mount.1.gz", "usr/share/man/man1/", "644"],
["target/release/manpages/rage.1.gz", "usr/share/man/man1/", "644"],
["target/release/manpages/rage-keygen.1.gz", "usr/share/man/man1/", "644"],
["target/release/manpages/rage-mount.1.gz", "usr/share/man/man1/", "644"],
["../README.md", "usr/share/doc/rage/README.md", "644"],
]
features = ["mount"]
Expand Down Expand Up @@ -78,14 +78,14 @@ zip = { version = "0.6.2", optional = true }
[build-dependencies]
clap = { workspace = true, features = ["string", "unstable-styles"] }
clap_complete = "4"
clap_mangen = "0.2"
flate2 = "1"
i18n-embed = { workspace = true, features = ["desktop-requester"] }
i18n-embed-fl.workspace = true
lazy_static.workspace = true
rust-embed.workspace = true

[dev-dependencies]
flate2 = "1"
man = "0.3"
trycmd = "0.14"

[features]
Expand Down
161 changes: 161 additions & 0 deletions rage/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ use std::path::PathBuf;

use clap::{Command, CommandFactory, ValueEnum};
use clap_complete::{generate_to, Shell};
use clap_mangen::{
roff::{Inline, Roff},
Man,
};
use flate2::{write::GzEncoder, Compression};

mod i18n {
include!("src/bin/rage/i18n.rs");
Expand All @@ -31,6 +36,47 @@ macro_rules! fl {
}};
}

struct Example {
text: String,
cmd: &'static str,
output: Option<String>,
}

impl Example {
const fn new(text: String, cmd: &'static str, output: Option<String>) -> Self {
Self { text, cmd, output }
}
}

struct Examples<const N: usize>([Example; N]);

impl<const N: usize> Examples<N> {
fn render(self, w: &mut impl io::Write) -> io::Result<()> {
let mut roff = Roff::default();
roff.control("SH", ["EXAMPLES"]);
for example in self.0 {
roff.control("TP", []);
roff.text(

Check warning on line 59 in rage/build.rs

View check run for this annotation

Codecov / codecov/patch

rage/build.rs#L54-L59

Added lines #L54 - L59 were not covered by tests
[
Inline::Roman(format!("{}:", example.text)),
Inline::LineBreak,
Inline::Bold(format!("$ {}", example.cmd)),
Inline::LineBreak,

Check warning on line 64 in rage/build.rs

View check run for this annotation

Codecov / codecov/patch

rage/build.rs#L61-L64

Added lines #L61 - L64 were not covered by tests
]
.into_iter()
.chain(
example
.output
.into_iter()
.flat_map(|output| [Inline::Roman(output), Inline::LineBreak]),

Check warning on line 71 in rage/build.rs

View check run for this annotation

Codecov / codecov/patch

rage/build.rs#L66-L71

Added lines #L66 - L71 were not covered by tests
)
.collect::<Vec<_>>(),

Check warning on line 73 in rage/build.rs

View check run for this annotation

Codecov / codecov/patch

rage/build.rs#L73

Added line #L73 was not covered by tests
);
}
roff.to_writer(w)

Check warning on line 76 in rage/build.rs

View check run for this annotation

Codecov / codecov/patch

rage/build.rs#L76

Added line #L76 was not covered by tests
}
}

#[derive(Clone)]
struct Cli {
rage: Command,
Expand Down Expand Up @@ -58,6 +104,120 @@ impl Cli {

Ok(())
}

fn generate_manpages(self, out_dir: &Path) -> io::Result<()> {
fs::create_dir_all(out_dir)?;

fn generate_manpage(
out_dir: &Path,
name: &str,
cmd: Command,
custom: impl FnOnce(&Man, &mut GzEncoder<fs::File>) -> io::Result<()>,
) -> io::Result<()> {
let file = fs::File::create(out_dir.join(format!("{}.1.gz", name)))?;
let mut w = GzEncoder::new(file, Compression::best());

let man = Man::new(cmd);
man.render_title(&mut w)?;
man.render_name_section(&mut w)?;
man.render_synopsis_section(&mut w)?;
man.render_options_section(&mut w)?;
custom(&man, &mut w)?;
man.render_version_section(&mut w)?;
man.render_authors_section(&mut w)
}

generate_manpage(
out_dir,
"rage",
self.rage
.about(fl!("man-rage-about"))
.after_help(rage::after_help_content("rage-keygen")),
|man, w| {
man.render_extra_section(w)?;
Examples([
Example::new(
fl!("man-rage-example-enc-single"),
"echo \"_o/\" | rage -o hello.age -r age1uvscypafkkxt6u2gkguxet62cenfmnpc0smzzlyun0lzszfatawq4kvf2u",
None,
),
Example::new(
fl!("man-rage-example-enc-multiple"),
"echo \"_o/\" | rage -r age1uvscypafkkxt6u2gkguxet62cenfmnpc0smzzlyun0lzszfatawq4kvf2u \
-r age1ex4ty8ppg02555at009uwu5vlk5686k3f23e7mac9z093uvzfp8sxr5jum > hello.age",
None,
),
Example::new(
fl!("man-rage-example-enc-password"),
"rage -p -o hello.txt.age hello.txt",
Some(format!("{}:", fl!("type-passphrase"))),
),
Example::new(
fl!("man-rage-example-enc-list"),
"tar cv ~/xxx | rage -R recipients.txt > xxx.tar.age",
None,
),
Example::new(
fl!("man-rage-example-enc-identities"),
"tar cv ~/xxx | rage -e -i keyA.txt -i keyB.txt > xxx.tar.age",
None,
),
Example::new(
fl!("man-rage-example-enc-url"),
"echo \"_o/\" | rage -o hello.age -R <(curl https://github.com/str4d.keys)",
None,
),
Example::new(
fl!("man-rage-example-dec-identities"),
"rage -d -o hello -i keyA.txt -i keyB.txt hello.age",
None,
),
])
.render(w)
},
)?;
generate_manpage(
out_dir,
"rage-keygen",
self.rage_keygen.about(fl!("man-keygen-about")),
|_, w| {
Examples([
Example::new(fl!("man-keygen-example-stdout"), "rage-keygen", None),
Example::new(
fl!("man-keygen-example-file"),
"rage-keygen -o key.txt",
Some(format!(
"{}: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p",
fl!("tty-pubkey")
)),
),
])
.render(w)
},
)?;
generate_manpage(
out_dir,
"rage-mount",
self.rage_mount.about(fl!("man-mount-about")),
|_, w| {
Examples([
Example::new(
fl!("man-mount-example-identity"),
"rage-mount -t tar -i key.txt encrypted.tar.age ./tmp",
None,
),
Example::new(
fl!("man-mount-example-passphrase"),
"rage-mount -t zip encrypted.zip.age ./tmp",
Some(format!("{}:", fl!("type-passphrase"))),
),
])
.render(w)
},
)?;

Ok(())
}
}

fn main() -> io::Result<()> {
Expand All @@ -77,6 +237,7 @@ fn main() -> io::Result<()> {

let mut cli = Cli::build();
cli.generate_completions(&out_dir.join("completions"))?;
cli.generate_manpages(&out_dir.join("manpages"))?;

Ok(())
}
Loading

0 comments on commit 91a5818

Please sign in to comment.