rage: Build manpages in the build script

This commit is contained in:
Jack Grigg 2024-01-09 04:35:03 +00:00
parent 0a6cb7972b
commit 91a5818110
14 changed files with 249 additions and 274 deletions

View file

@ -190,9 +190,6 @@ jobs:
run: cargo build --release --locked --target ${{ matrix.target }} ${{ matrix.build_flags }} run: cargo build --release --locked --target ${{ matrix.target }} ${{ matrix.build_flags }}
working-directory: ./rage working-directory: ./rage
- name: Generate manpages
run: cargo run --example generate-docs
- name: Update Debian package config for cross-compile - name: Update Debian package config for cross-compile
run: sed -i '/\/rage-mount/d' rage/Cargo.toml run: sed -i '/\/rage-mount/d' rage/Cargo.toml
if: matrix.name != 'linux' if: matrix.name != 'linux'

25
Cargo.lock generated
View file

@ -540,6 +540,16 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "clap_mangen"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f2e32b579dae093c2424a8b7e2bea09c89da01e1ce5065eb2f0a6f1cc15cc1f"
dependencies = [
"clap",
"roff",
]
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.0" version = "1.0.0"
@ -1472,15 +1482,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "man"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebf5fa795187a80147b1ac10aaedcf5ffd3bbeb1838bda61801a1c9ad700a1c9"
dependencies = [
"roff",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.1" version = "2.7.1"
@ -1998,6 +1999,7 @@ dependencies = [
"chrono", "chrono",
"clap", "clap",
"clap_complete", "clap_complete",
"clap_mangen",
"console", "console",
"ctrlc", "ctrlc",
"env_logger", "env_logger",
@ -2009,7 +2011,6 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"log", "log",
"man",
"pinentry", "pinentry",
"rust-embed", "rust-embed",
"tar", "tar",
@ -2126,9 +2127,9 @@ dependencies = [
[[package]] [[package]]
name = "roff" name = "roff"
version = "0.1.0" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33e4fb37ba46888052c763e4ec2acfedd8f00f62897b630cadb6298b833675e" checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
[[package]] [[package]]
name = "rpassword" name = "rpassword"

View file

@ -33,9 +33,9 @@ assets = [
["target/release/completions/_rage", "usr/share/zsh/functions/Completion/Debian/", "644"], ["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-keygen", "usr/share/zsh/functions/Completion/Debian/", "644"],
["target/release/completions/_rage-mount", "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/release/manpages/rage.1.gz", "usr/share/man/man1/", "644"],
["../target/manpages/rage-keygen.1.gz", "usr/share/man/man1/", "644"], ["target/release/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-mount.1.gz", "usr/share/man/man1/", "644"],
["../README.md", "usr/share/doc/rage/README.md", "644"], ["../README.md", "usr/share/doc/rage/README.md", "644"],
] ]
features = ["mount"] features = ["mount"]
@ -78,14 +78,14 @@ zip = { version = "0.6.2", optional = true }
[build-dependencies] [build-dependencies]
clap = { workspace = true, features = ["string", "unstable-styles"] } clap = { workspace = true, features = ["string", "unstable-styles"] }
clap_complete = "4" clap_complete = "4"
clap_mangen = "0.2"
flate2 = "1"
i18n-embed = { workspace = true, features = ["desktop-requester"] } i18n-embed = { workspace = true, features = ["desktop-requester"] }
i18n-embed-fl.workspace = true i18n-embed-fl.workspace = true
lazy_static.workspace = true lazy_static.workspace = true
rust-embed.workspace = true rust-embed.workspace = true
[dev-dependencies] [dev-dependencies]
flate2 = "1"
man = "0.3"
trycmd = "0.14" trycmd = "0.14"
[features] [features]

View file

@ -6,6 +6,11 @@ use std::path::PathBuf;
use clap::{Command, CommandFactory, ValueEnum}; use clap::{Command, CommandFactory, ValueEnum};
use clap_complete::{generate_to, Shell}; use clap_complete::{generate_to, Shell};
use clap_mangen::{
roff::{Inline, Roff},
Man,
};
use flate2::{write::GzEncoder, Compression};
mod i18n { mod i18n {
include!("src/bin/rage/i18n.rs"); include!("src/bin/rage/i18n.rs");
@ -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(
[
Inline::Roman(format!("{}:", example.text)),
Inline::LineBreak,
Inline::Bold(format!("$ {}", example.cmd)),
Inline::LineBreak,
]
.into_iter()
.chain(
example
.output
.into_iter()
.flat_map(|output| [Inline::Roman(output), Inline::LineBreak]),
)
.collect::<Vec<_>>(),
);
}
roff.to_writer(w)
}
}
#[derive(Clone)] #[derive(Clone)]
struct Cli { struct Cli {
rage: Command, rage: Command,
@ -58,6 +104,120 @@ impl Cli {
Ok(()) 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<()> { fn main() -> io::Result<()> {
@ -77,6 +237,7 @@ fn main() -> io::Result<()> {
let mut cli = Cli::build(); let mut cli = Cli::build();
cli.generate_completions(&out_dir.join("completions"))?; cli.generate_completions(&out_dir.join("completions"))?;
cli.generate_manpages(&out_dir.join("manpages"))?;
Ok(()) Ok(())
} }

View file

@ -1,223 +0,0 @@
use flate2::{write::GzEncoder, Compression};
use man::prelude::*;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
const MANPAGES_DIR: &str = "./target/manpages";
fn generate_manpage(page: String, name: &str) {
let file = File::create(format!("{}/{}.1.gz", MANPAGES_DIR, name))
.expect("Should be able to open file in target directory");
let mut encoder = GzEncoder::new(file, Compression::best());
encoder
.write_all(page.as_bytes())
.expect("Should be able to write to file in target directory");
}
fn rage_page() {
let builder = Manual::new("rage")
.about("A simple, secure, and modern encryption tool")
.author(Author::new("Jack Grigg").email("thestr4d@gmail.com"))
.flag(
Flag::new()
.short("-h")
.long("--help")
.help("Display help text and exit."),
)
.flag(
Flag::new()
.short("-V")
.long("--version")
.help("Display version info and exit."),
)
.flag(
Flag::new()
.short("-e")
.long("--encrypt")
.help("Encrypt the input. By default, the input is encrypted."),
)
.flag(
Flag::new()
.short("-d")
.long("--decrypt")
.help("Decrypt the input. By default, the input is encrypted."),
)
.flag(
Flag::new()
.short("-p")
.long("--passphrase")
.help("Encrypt with a passphrase instead of recipients."),
)
.flag(
Flag::new()
.short("-a")
.long("--armor")
.help("Encrypt to a PEM encoded format."),
)
.option(
Opt::new("RECIPIENT")
.short("-r")
.long("--recipient")
.help("Encrypt to the specified RECIPIENT. May be repeated."),
)
.option(
Opt::new("PATH")
.short("-R")
.long("--recipients-file")
.help("Encrypt to the recipients listed at PATH. May be repeated."),
)
.option(
Opt::new("IDENTITY")
.short("-i")
.long("--identity")
.help("Use the identity file at IDENTITY. May be repeated."),
)
.option(
Opt::new("OUTPUT")
.short("-o")
.long("--output")
.help("Write the result to the file at path OUTPUT. Defaults to standard output."),
)
.option(
Opt::new("WF")
.long("--max-work-factor")
.help("The maximum work factor to allow for passphrase decryption."),
)
.arg(Arg::new("[INPUT_FILE (defaults to stdin)]"))
.example(Example::new().text("Encryption to a recipient").command(
"echo \"_o/\" | rage -o hello.age -r age1uvscypafkkxt6u2gkguxet62cenfmnpc0smzzlyun0lzszfatawq4kvf2u",
))
.example(
Example::new()
.text("Encryption to multiple recipients (with default output to stdout)")
.command(
"echo \"_o/\" | rage -r age1uvscypafkkxt6u2gkguxet62cenfmnpc0smzzlyun0lzszfatawq4kvf2u \
-r age1ex4ty8ppg02555at009uwu5vlk5686k3f23e7mac9z093uvzfp8sxr5jum > hello.age",
),
)
.example(
Example::new()
.text("Encryption with a password (interactive only, use recipients for batch!)")
.command("rage -p -o hello.txt.age hello.txt")
.output("Type passphrase:"),
)
.example(
Example::new()
.text("Encryption to a list of recipients in a file")
.command("tar cv ~/xxx | rage -R recipients.txt > xxx.tar.age"),
)
.example(
Example::new()
.text("Encryption to several identities")
.command("tar cv ~/xxx | rage -e -i keyA.txt -i keyB.txt > xxx.tar.age"),
)
.example(
Example::new()
.text("Encryption to a list of recipients at an HTTPS URL")
.command(
"echo \"_o/\" | rage -o hello.age -R <(curl https://github.com/str4d.keys)",
),
)
.example(
Example::new()
.text("Decryption with identities")
.command("rage -d -o hello -i keyA.txt -i keyB.txt hello.age"),
);
let page = builder.render();
generate_manpage(page, "rage");
}
fn rage_keygen_page() {
let page = Manual::new("rage-keygen")
.about("Generate age-compatible encryption key pairs")
.author(Author::new("Jack Grigg").email("thestr4d@gmail.com"))
.flag(
Flag::new()
.short("-h")
.long("--help")
.help("Display help text and exit."),
)
.flag(
Flag::new()
.short("-V")
.long("--version")
.help("Display version info and exit."),
)
.option(
Opt::new("OUTPUT").short("-o").long("--output").help(
"Write the key pair to the file at path OUTPUT. Defaults to standard output.",
),
)
.example(
Example::new()
.text("Generate a new key pair")
.command("rage-keygen"),
)
.example(
Example::new()
.text("Generate a new key pair and save it to a file")
.command("rage-keygen -o key.txt")
.output(
"Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p",
),
)
.render();
generate_manpage(page, "rage-keygen");
}
fn rage_mount_page() {
let page = Manual::new("rage-mount")
.about("Mount an age-encrypted filesystem")
.author(Author::new("Jack Grigg").email("thestr4d@gmail.com"))
.flag(
Flag::new()
.short("-h")
.long("--help")
.help("Display help text and exit."),
)
.flag(
Flag::new()
.short("-V")
.long("--version")
.help("Display version info and exit."),
)
.flag(
Flag::new()
.short("-t")
.long("--types")
.help("The type of the filesystem (one of \"tar\", \"zip\")."),
)
.option(
Opt::new("IDENTITY")
.short("-i")
.long("--identity")
.help("Use the private key file at IDENTITY. May be repeated."),
)
.arg(Arg::new("filename"))
.arg(Arg::new("mountpoint"))
.example(
Example::new()
.text("Mounting an archive encrypted to a recipient")
.command("rage-mount -t tar -i key.txt encrypted.tar.age ./tmp"),
)
.example(
Example::new()
.text("Mounting an archive encrypted with a passphrase")
.command("rage-mount -t zip encrypted.zip.age ./tmp")
.output("Type passphrase:"),
)
.render();
generate_manpage(page, "rage-mount");
}
fn main() {
// Create the target directory if it does not exist.
let _ = create_dir_all(MANPAGES_DIR);
rage_page();
rage_keygen_page();
rage_mount_page();
}

View file

@ -56,12 +56,12 @@ help-flag-identity = Use the identity file at {identity}. May be repeated.
help-flag-plugin-name = Use {-age-plugin-}{plugin-name} in its default mode as an identity. help-flag-plugin-name = Use {-age-plugin-}{plugin-name} in its default mode as an identity.
help-flag-output = Write the result to the file at path {output}. help-flag-output = Write the result to the file at path {output}.
rage-after-help = rage-after-help-content =
{input} defaults to standard input, and {output} defaults to standard output. {input} defaults to standard input, and {output} defaults to standard output.
{recipient} can be: {recipient} can be:
- An {-age} public key, as generated by {$keygen_name} ("age1..."). - An {-age} public key, as generated by {$keygen_name} ({$example_age_pubkey}).
- An SSH public key ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). - An SSH public key ({$example_ssh_pubkey}).
{recipients-file} is a path to a file containing {-age} recipients, one per line {recipients-file} is a path to a file containing {-age} recipients, one per line
(ignoring "#" prefixed comments and empty lines). (ignoring "#" prefixed comments and empty lines).
@ -71,6 +71,7 @@ rage-after-help =
Passphrase-encrypted {-age} identity files can be used as identity files. Passphrase-encrypted {-age} identity files can be used as identity files.
Multiple identities may be provided, and any unused ones will be ignored. Multiple identities may be provided, and any unused ones will be ignored.
rage-after-help-example =
Example: Example:
{" "}{$example_a} {" "}{$example_a}
{" "}{tty-pubkey}: {$example_a_output} {" "}{tty-pubkey}: {$example_a_output}
@ -197,3 +198,25 @@ err-mnt-unknown-type = Unknown filesystem type "{$fs_type}"
## Unstable features ## Unstable features
test-unstable = To test this, build {-rage} with {-flag-unstable}. test-unstable = To test this, build {-rage} with {-flag-unstable}.
## Manpages
man-rage-about = A simple, secure, and modern encryption tool
man-rage-example-enc-single = Encryption to a recipient
man-rage-example-enc-multiple = Encryption to multiple recipients (with default output to stdout)
man-rage-example-enc-password = Encryption with a password (interactive only, use recipients for batch!)
man-rage-example-enc-list = Encryption to a list of recipients in a file
man-rage-example-enc-identities = Encryption to several identities
man-rage-example-enc-url = Encryption to a list of recipients at an HTTPS URL
man-rage-example-dec-identities = Decryption with identities
man-keygen-about = Generate age-compatible encryption key pairs
man-keygen-example-stdout = Generate a new key pair
man-keygen-example-file = Generate a new key pair and save it to a file
man-mount-about = Mount an age-encrypted filesystem
man-mount-example-identity = Mounting an archive encrypted to a recipient
man-mount-example-passphrase = Mounting an archive encrypted with a passphrase

View file

@ -37,12 +37,12 @@ plugin-name = PLUGIN-NAME
input = INPUT input = INPUT
output = OUTPUT output = OUTPUT
rage-after-help = rage-after-help-content =
{input} por defecto a standard input, y {output} por defecto standard output. {input} por defecto a standard input, y {output} por defecto standard output.
{recipient} puede ser: {recipient} puede ser:
- Una clave pública {-age}, como es generada por {$keygen_name} ("age1..."). - Una clave pública {-age}, como es generada por {$keygen_name} ({$example_age_pubkey}).
- Una clave pública SSH ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). - Una clave pública SSH ({$example_ssh_pubkey}).
{recipients-file} es una ruta a un archivo que contenga un destinatario {-age} por línea {recipients-file} es una ruta a un archivo que contenga un destinatario {-age} por línea
(ignorando comentarios con el prefijo "#" y líneas vacías). (ignorando comentarios con el prefijo "#" y líneas vacías).
@ -54,6 +54,7 @@ rage-after-help =
Pueden proveerse múltiples idendidades, cualquiera que no sea Pueden proveerse múltiples idendidades, cualquiera que no sea
utilizada será ignorada. utilizada será ignorada.
rage-after-help-example =
Ejemplo: Ejemplo:
{" "}{$example_a} {" "}{$example_a}
{" "}{tty-pubkey}: {$example_a_output} {" "}{tty-pubkey}: {$example_a_output}

View file

@ -37,13 +37,13 @@ plugin-name = PLUGIN-NAME
input = INPUT input = INPUT
output = OUTPUT output = OUTPUT
rage-after-help = rage-after-help-content =
{input} ha come valore predefinito lo standard input, e {output} ha come {input} ha come valore predefinito lo standard input, e {output} ha come
valore predefinito lo standard output. valore predefinito lo standard output.
{recipient} può essere: {recipient} può essere:
- Una chiave pubblica {-age}, come generata da {$keygen_name} ("age1..."). - Una chiave pubblica {-age}, come generata da {$keygen_name} ({$example_age_pubkey}).
- Una chiave pubblica SSH ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). - Una chiave pubblica SSH ({$example_ssh_pubkey}).
{recipients-file} è il percorso ad un file contenente dei destinatari {-age}, {recipients-file} è il percorso ad un file contenente dei destinatari {-age},
uno per riga (ignorando i commenti che iniziano con "#" e le righe vuote). uno per riga (ignorando i commenti che iniziano con "#" e le righe vuote).
@ -54,6 +54,7 @@ rage-after-help =
I file di identità possono essere cifrati con {-age} e una passphrase. I file di identità possono essere cifrati con {-age} e una passphrase.
Possono essere fornite più identità, quelle inutilizzate verranno ignorate. Possono essere fornite più identità, quelle inutilizzate verranno ignorate.
rage-after-help-example =
Esempio: Esempio:
{" "}{$example_a} {" "}{$example_a}
{" "}{tty-pubkey}: {$example_a_output} {" "}{tty-pubkey}: {$example_a_output}

View file

@ -37,12 +37,12 @@ plugin-name = PLUGIN-NAME
input = INPUT input = INPUT
output = OUTPUT output = OUTPUT
rage-after-help = rage-after-help-content =
{input} 默认为标准输入 (stdin), 而 {output} 默认为标准输出 (stdout) 。 {input} 默认为标准输入 (stdin), 而 {output} 默认为标准输出 (stdout) 。
{recipient} 可为: {recipient} 可为:
- 一把以 {$keygen_name} 生成的 {-age} 公钥 ("age1...")。 - 一把以 {$keygen_name} 生成的 {-age} 公钥 ({$example_age_pubkey})。
- 一把 SSH 公钥 ("ssh-ed25519 AAAA...", "ssh-rsa AAAA...")。 - 一把 SSH 公钥 ({$example_ssh_pubkey})。
{recipients-file} 是一个文件路径。该文件应含有 {-age} 接收方, 每行一个 {recipients-file} 是一个文件路径。该文件应含有 {-age} 接收方, 每行一个
(前缀为 "#" 的注释以及空行将被忽略)。 (前缀为 "#" 的注释以及空行将被忽略)。
@ -52,6 +52,7 @@ rage-after-help =
Passphrase-encrypted {-age} identity files can be used as identity files. Passphrase-encrypted {-age} identity files can be used as identity files.
您可提供多份身份, 未使用的身份将被忽略。 您可提供多份身份, 未使用的身份将被忽略。
rage-after-help-example =
Example: Example:
{" "}{$example_a} {" "}{$example_a}
{" "}{tty-pubkey}: {$example_a_output} {" "}{tty-pubkey}: {$example_a_output}

View file

@ -37,12 +37,12 @@ plugin-name = PLUGIN-NAME
input = INPUT input = INPUT
output = OUTPUT output = OUTPUT
rage-after-help = rage-after-help-content =
{input} 默認為標準輸入 (stdin), 而 {output} 默認為標準輸出 (stdout) 。 {input} 默認為標準輸入 (stdin), 而 {output} 默認為標準輸出 (stdout) 。
{recipient} 可為: {recipient} 可為:
- 一把以 {$keygen_name} 生成的 {-age} 公鑰 ("age1...")。 - 一把以 {$keygen_name} 生成的 {-age} 公鑰 ({$example_age_pubkey})。
- 一把 SSH 公鑰 ("ssh-ed25519 AAAA...", "ssh-rsa AAAA...")。 - 一把 SSH 公鑰 ({$example_ssh_pubkey})。
{recipients-file} 是一個文件路徑。該文件應含有 {-age} 接收方, 每行一個 {recipients-file} 是一個文件路徑。該文件應含有 {-age} 接收方, 每行一個
(前綴為 "#" 的注釋以及空行將被忽略)。 (前綴為 "#" 的注釋以及空行將被忽略)。
@ -52,6 +52,7 @@ rage-after-help =
Passphrase-encrypted {-age} identity files can be used as identity files. Passphrase-encrypted {-age} identity files can be used as identity files.
您可提供多份身份, 未使用的身份將被忽略。 您可提供多份身份, 未使用的身份將被忽略。
rage-after-help-example =
Example: Example:
{" "}{$example_a} {" "}{$example_a}
{" "}{tty-pubkey}: {$example_a_output} {" "}{tty-pubkey}: {$example_a_output}

View file

@ -5,7 +5,7 @@ use crate::fl;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command(display_name = "rage-keygen")] #[command(display_name = "rage-keygen")]
#[command(name = "rage-keygen")] #[command(name = "rage-keygen")]
#[command(version)] #[command(author, version)]
#[command(help_template = format!("\ #[command(help_template = format!("\
{{before-help}}{{about-with-newline}} {{before-help}}{{about-with-newline}}
{}{}:{} {{usage}} {}{}:{} {{usage}}

View file

@ -5,7 +5,7 @@ use crate::fl;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command(display_name = "rage-mount")] #[command(display_name = "rage-mount")]
#[command(name = "rage-mount")] #[command(name = "rage-mount")]
#[command(version)] #[command(author, version)]
#[command(help_template = format!("\ #[command(help_template = format!("\
{{before-help}}{{about-with-newline}} {{before-help}}{{about-with-newline}}
{}{}:{} {{usage}} {}{}:{} {{usage}}

View file

@ -29,6 +29,15 @@ fn usage() -> String {
) )
} }
pub(crate) fn after_help_content(keygen_name: &str) -> String {
fl!(
"rage-after-help-content",
keygen_name = keygen_name,
example_age_pubkey = "\"age1...\"",
example_ssh_pubkey = "\"ssh-ed25519 AAAA...\", \"ssh-rsa AAAA...\"",
)
}
fn after_help() -> String { fn after_help() -> String {
let binary_name = binary_name(); let binary_name = binary_name();
let keygen_name = format!("{}-keygen", binary_name); let keygen_name = format!("{}-keygen", binary_name);
@ -43,18 +52,21 @@ fn after_help() -> String {
binary_name, binary_name,
); );
fl!( format!(
"rage-after-help", "{}\n\n{}",
keygen_name = keygen_name, after_help_content(&keygen_name),
example_a = example_a, fl!(
example_a_output = example_a_output, "rage-after-help-example",
example_b = example_b, example_a = example_a,
example_c = example_c, example_a_output = example_a_output,
example_b = example_b,
example_c = example_c,
),
) )
} }
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command(version)] #[command(author, version)]
#[command(help_template = format!("\ #[command(help_template = format!("\
{{before-help}}{{about-with-newline}} {{before-help}}{{about-with-newline}}
{}{}:{} {{usage}} {}{}:{} {{usage}}

View file

@ -189,6 +189,10 @@ criteria = "safe-to-deploy"
version = "0.5.0" version = "0.5.0"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"
[[exemptions.clap_mangen]]
version = "0.2.12"
criteria = "safe-to-deploy"
[[exemptions.console]] [[exemptions.console]]
version = "0.15.7" version = "0.15.7"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"
@ -433,10 +437,6 @@ criteria = "safe-to-deploy"
version = "0.4.11" version = "0.4.11"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"
[[exemptions.man]]
version = "0.3.0"
criteria = "safe-to-run"
[[exemptions.memchr]] [[exemptions.memchr]]
version = "2.6.3" version = "2.6.3"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"
@ -610,8 +610,8 @@ version = "0.8.37"
criteria = "safe-to-run" criteria = "safe-to-run"
[[exemptions.roff]] [[exemptions.roff]]
version = "0.1.0" version = "0.2.1"
criteria = "safe-to-run" criteria = "safe-to-deploy"
[[exemptions.rpassword]] [[exemptions.rpassword]]
version = "7.3.1" version = "7.3.1"