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:
parent
0816badf3a
commit
7f2e247f55
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(())
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue