1
0
Fork 0
mirror of https://github.com/BLAKE3-team/BLAKE3 synced 2024-05-12 14:46:15 +02:00

Generate `b3sum(1)` at build time

This commit is contained in:
Shun Sakai 2024-04-24 14:37:00 +09:00
parent 0816badf3a
commit 7f2e247f55
5 changed files with 181 additions and 92 deletions

17
b3sum/Cargo.lock generated
View File

@ -75,6 +75,7 @@ dependencies = [
"anyhow",
"blake3",
"clap",
"clap_mangen",
"duct",
"hex",
"rayon",
@ -154,6 +155,16 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "clap_mangen"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1dd95b5ebb5c1c54581dd6346f3ed6a79a3eef95dd372fc2ac13d535535300e"
dependencies = [
"clap",
"roff",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
@ -318,6 +329,12 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "roff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
[[package]]
name = "rustix"
version = "0.38.31"

View File

@ -24,3 +24,8 @@ wild = "2.0.3"
[dev-dependencies]
duct = "0.13.3"
tempfile = "3.1.0"
[build-dependencies]
blake3 = { version = "1", path = ".." }
clap = { version = "4.0.8", features = ["derive"] }
clap_mangen = "0.2.20"

59
b3sum/build.rs Normal file
View File

@ -0,0 +1,59 @@
use clap::CommandFactory;
include!("src/cli.rs");
fn generate_man_page(out_dir: &std::path::Path) -> std::io::Result<()> {
let command = Inner::command();
let man = clap_mangen::Man::new(command).date("2024-04-24");
let mut buf = Vec::new();
man.render_title(&mut buf)?;
// The NAME section.
let mut roff = clap_mangen::roff::Roff::new();
roff.control("SH", ["NAME"]);
roff.text([clap_mangen::roff::roman(
"b3sum - compute and check BLAKE3 message digest",
)]);
roff.to_writer(&mut buf)?;
// The SYNOPSIS section.
let mut roff = clap_mangen::roff::Roff::new();
roff.control("SH", ["SYNOPSIS"]);
roff.text([
clap_mangen::roff::bold("b3sum"),
clap_mangen::roff::roman(" ["),
clap_mangen::roff::italic("OPTIONS"),
clap_mangen::roff::roman("] ["),
clap_mangen::roff::italic("FILE"),
clap_mangen::roff::roman("]..."),
]);
roff.to_writer(&mut buf)?;
man.render_description_section(&mut buf)?;
man.render_options_section(&mut buf)?;
// The SEE ALSO section.
let mut roff = clap_mangen::roff::Roff::new();
roff.control("SH", ["SEE ALSO"]);
roff.text([
clap_mangen::roff::bold("b2sum"),
clap_mangen::roff::roman("(1), "),
clap_mangen::roff::bold("md5sum"),
clap_mangen::roff::roman("(1)"),
]);
roff.to_writer(&mut buf)?;
std::fs::write(out_dir.join("b3sum.1"), buf)?;
Ok(())
}
fn main() -> std::io::Result<()> {
println!("cargo:rerun-if-changed=src/cli.rs");
let out_dir = std::env::var("OUT_DIR").expect("environment variable `OUT_DIR` not defined");
let out_dir = std::path::PathBuf::from(out_dir);
generate_man_page(&out_dir)?;
Ok(())
}

96
b3sum/src/cli.rs Normal file
View File

@ -0,0 +1,96 @@
use clap::Parser;
use std::path::PathBuf;
const DERIVE_KEY_ARG: &str = "derive_key";
const KEYED_ARG: &str = "keyed";
const LENGTH_ARG: &str = "length";
const NO_NAMES_ARG: &str = "no_names";
const RAW_ARG: &str = "raw";
const CHECK_ARG: &str = "check";
/// Print or check BLAKE3 checksums.
///
/// With no FILE, or when FILE is -, read standard input.
#[derive(Parser)]
#[command(version, max_term_width(100))]
pub struct Inner {
/// Files to hash, or checkfiles to check
///
/// When no file is given, or when - is given, read standard input.
pub file: Vec<PathBuf>,
/// Use the keyed mode, reading the 32-byte key from stdin
#[arg(long, requires("file"))]
pub keyed: bool,
/// Use the key derivation mode, with the given context string
///
/// Cannot be used with --keyed.
#[arg(long, value_name("CONTEXT"), conflicts_with(KEYED_ARG))]
pub derive_key: Option<String>,
/// The number of output bytes, before hex encoding
#[arg(
short,
long,
default_value_t = blake3::OUT_LEN as u64,
value_name("LEN")
)]
pub length: u64,
/// The starting output byte offset, before hex encoding
#[arg(long, default_value_t = 0, value_name("SEEK"))]
pub seek: u64,
/// The maximum number of threads to use
///
/// By default, this is the number of logical cores. If this flag is
/// omitted, or if its value is 0, RAYON_NUM_THREADS is also respected.
#[arg(long, value_name("NUM"))]
pub num_threads: Option<usize>,
/// Disable memory mapping
///
/// Currently this also disables multithreading.
#[arg(long)]
pub no_mmap: bool,
/// Omit filenames in the output
#[arg(long)]
pub no_names: bool,
/// Write raw output bytes to stdout, rather than hex
///
/// --no-names is implied. In this case, only a single input is allowed.
#[arg(long)]
pub raw: bool,
/// Read BLAKE3 sums from the [FILE]s and check them
#[arg(
short,
long,
conflicts_with(DERIVE_KEY_ARG),
conflicts_with(KEYED_ARG),
conflicts_with(LENGTH_ARG),
conflicts_with(RAW_ARG),
conflicts_with(NO_NAMES_ARG)
)]
pub check: bool,
/// Skip printing OK for each checked file
///
/// Must be used with --check.
#[arg(long, requires(CHECK_ARG))]
pub quiet: bool,
}
#[cfg(test)]
mod test {
use super::*;
use clap::CommandFactory;
#[test]
fn test_args() {
Inner::command().debug_assert();
}
}

View File

@ -6,93 +6,15 @@ use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
mod cli;
#[cfg(test)]
mod unit_tests;
const NAME: &str = "b3sum";
const DERIVE_KEY_ARG: &str = "derive_key";
const KEYED_ARG: &str = "keyed";
const LENGTH_ARG: &str = "length";
const NO_NAMES_ARG: &str = "no_names";
const RAW_ARG: &str = "raw";
const CHECK_ARG: &str = "check";
#[derive(Parser)]
#[command(version, max_term_width(100))]
struct Inner {
/// Files to hash, or checkfiles to check
///
/// When no file is given, or when - is given, read standard input.
file: Vec<PathBuf>,
/// Use the keyed mode, reading the 32-byte key from stdin
#[arg(long, requires("file"))]
keyed: bool,
/// Use the key derivation mode, with the given context string
///
/// Cannot be used with --keyed.
#[arg(long, value_name("CONTEXT"), conflicts_with(KEYED_ARG))]
derive_key: Option<String>,
/// The number of output bytes, before hex encoding
#[arg(
short,
long,
default_value_t = blake3::OUT_LEN as u64,
value_name("LEN")
)]
length: u64,
/// The starting output byte offset, before hex encoding
#[arg(long, default_value_t = 0, value_name("SEEK"))]
seek: u64,
/// The maximum number of threads to use
///
/// By default, this is the number of logical cores. If this flag is
/// omitted, or if its value is 0, RAYON_NUM_THREADS is also respected.
#[arg(long, value_name("NUM"))]
num_threads: Option<usize>,
/// Disable memory mapping
///
/// Currently this also disables multithreading.
#[arg(long)]
no_mmap: bool,
/// Omit filenames in the output
#[arg(long)]
no_names: bool,
/// Write raw output bytes to stdout, rather than hex
///
/// --no-names is implied. In this case, only a single input is allowed.
#[arg(long)]
raw: bool,
/// Read BLAKE3 sums from the [FILE]s and check them
#[arg(
short,
long,
conflicts_with(DERIVE_KEY_ARG),
conflicts_with(KEYED_ARG),
conflicts_with(LENGTH_ARG),
conflicts_with(RAW_ARG),
conflicts_with(NO_NAMES_ARG)
)]
check: bool,
/// Skip printing OK for each checked file
///
/// Must be used with --check.
#[arg(long, requires(CHECK_ARG))]
quiet: bool,
}
struct Args {
inner: Inner,
inner: crate::cli::Inner,
file_args: Vec<PathBuf>,
base_hasher: blake3::Hasher,
}
@ -101,7 +23,7 @@ impl Args {
fn parse() -> Result<Self> {
// wild::args_os() is equivalent to std::env::args_os() on Unix,
// but on Windows it adds support for globbing.
let inner = Inner::parse_from(wild::args_os());
let inner = crate::cli::Inner::parse_from(wild::args_os());
let file_args = if !inner.file.is_empty() {
inner.file.clone()
} else {
@ -509,13 +431,3 @@ fn main() -> Result<()> {
std::process::exit(if files_failed > 0 { 1 } else { 0 });
})
}
#[cfg(test)]
mod test {
use clap::CommandFactory;
#[test]
fn test_args() {
crate::Inner::command().debug_assert();
}
}