b2sum: introduce standalone binary

This commit is contained in:
Dorian Peron
2026-01-28 10:14:01 +01:00
parent a968342d42
commit d22c7e14ec
19 changed files with 405 additions and 6 deletions
Generated
+13
View File
@@ -556,6 +556,7 @@ dependencies = [
"unicode-width 0.2.2",
"unindent",
"uu_arch",
"uu_b2sum",
"uu_base32",
"uu_base64",
"uu_basename",
@@ -3172,6 +3173,18 @@ dependencies = [
"uucore",
]
[[package]]
name = "uu_b2sum"
version = "0.6.0"
dependencies = [
"clap",
"codspeed-divan-compat",
"fluent",
"tempfile",
"uu_checksum_common",
"uucore",
]
[[package]]
name = "uu_base32"
version = "0.6.0"
+2
View File
@@ -86,6 +86,7 @@ feat_common_core = [
"basenc",
"cat",
"cksum",
"b2sum",
"md5sum",
"comm",
"cp",
@@ -438,6 +439,7 @@ chmod = { optional = true, version = "0.6.0", package = "uu_chmod", path = "src/
chown = { optional = true, version = "0.6.0", package = "uu_chown", path = "src/uu/chown" }
chroot = { optional = true, version = "0.6.0", package = "uu_chroot", path = "src/uu/chroot" }
cksum = { optional = true, version = "0.6.0", package = "uu_cksum", path = "src/uu/cksum" }
b2sum = { optional = true, version = "0.6.0", package = "uu_b2sum", path = "src/uu/b2sum" }
md5sum = { optional = true, version = "0.6.0", package = "uu_md5sum", path = "src/uu/md5sum" }
comm = { optional = true, version = "0.6.0", package = "uu_comm", path = "src/uu/comm" }
cp = { optional = true, version = "0.6.0", package = "uu_cp", path = "src/uu/cp" }
-1
View File
@@ -96,7 +96,6 @@ SELINUX_PROGS := \
runcon
HASHSUM_PROGS := \
b2sum \
sha1sum \
sha224sum \
sha256sum \
-1
View File
@@ -96,7 +96,6 @@ pub fn main() {
phf_map.entry("sha256sum", map_value.clone());
phf_map.entry("sha384sum", map_value.clone());
phf_map.entry("sha512sum", map_value.clone());
phf_map.entry("b2sum", map_value.clone());
}
_ => {
phf_map.entry(krate, map_value.clone());
+1 -1
View File
@@ -51,7 +51,7 @@ fn get_canonical_util_name(util_name: &str) -> &str {
"[" => "test",
// hashsum aliases - all these hash commands are aliases for hashsum
"sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" | "b2sum" => "hashsum",
"sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" => "hashsum",
"dir" => "ls", // dir is an alias for ls
+38
View File
@@ -0,0 +1,38 @@
[package]
name = "uu_b2sum"
description = "b2sum ~ (uutils) Print or check the BLAKE2b checksums"
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/b2sum"
version.workspace = true
authors.workspace = true
license.workspace = true
homepage.workspace = true
keywords.workspace = true
categories.workspace = true
edition.workspace = true
readme.workspace = true
[lints]
workspace = true
[lib]
path = "src/b2sum.rs"
[dependencies]
clap = { workspace = true }
uu_checksum_common = { workspace = true }
uucore = { workspace = true, features = [
"checksum",
"encoding",
"sum",
"hardware",
] }
fluent = { workspace = true }
[dev-dependencies]
divan = { workspace = true }
tempfile = { workspace = true }
uucore = { workspace = true, features = ["benchmark"] }
[[bin]]
name = "b2sum"
path = "src/main.rs"
+1
View File
@@ -0,0 +1 @@
../../../LICENSE
+2
View File
@@ -0,0 +1,2 @@
b2sum-about = Print or check the BLAKE2b checksums
b2sum-usage = b2sum [OPTIONS] [FILE]...
+2
View File
@@ -0,0 +1,2 @@
b2sum-about = Afficher le BLAKE2b et la taille de chaque fichier
b2sum-usage = b2sum [OPTION]... [FICHIER]...
+29
View File
@@ -0,0 +1,29 @@
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (ToDO) algo
use clap::Command;
use uu_checksum_common::{standalone_checksum_app_with_length, standalone_with_length_main};
use uucore::checksum::{AlgoKind, calculate_blake2b_length_str};
use uucore::error::UResult;
use uucore::translate;
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
standalone_with_length_main(
AlgoKind::Blake2b,
uu_app(),
args,
calculate_blake2b_length_str,
)
}
#[inline]
pub fn uu_app() -> Command {
standalone_checksum_app_with_length(translate!("b2sum-about"), translate!("b2sum-usage"))
}
+1
View File
@@ -0,0 +1 @@
uucore::bin!(uu_b2sum);
+1 -1
View File
@@ -173,7 +173,7 @@ pub fn get_canonical_util_name(util_name: &str) -> &str {
"[" => "test",
// hashsum aliases - all these hash commands are aliases for hashsum
"sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" | "b2sum" => "hashsum",
"sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" => "hashsum",
"dir" => "ls", // dir is an alias for ls
+1 -1
View File
@@ -157,7 +157,7 @@ fn create_bundle(
try_add_resource_from(get_locales_dir(util_name).ok());
// checksum binaries also require fluent files from the checksum_common crate
if ["cksum", "md5sum"].contains(&util_name) {
if ["cksum", "b2sum", "md5sum"].contains(&util_name) {
try_add_resource_from(get_locales_dir("checksum_common").ok());
}
+299
View File
@@ -0,0 +1,299 @@
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use rstest::rstest;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
// spell-checker:ignore checkfile, testf, ntestf
macro_rules! get_hash(
($str:expr) => (
$str.split(' ').collect::<Vec<&str>>()[0]
);
);
macro_rules! test_digest_with_len {
($id:ident, $size:expr) => {
mod $id {
use uutests::util::*;
use uutests::util_name;
static LENGTH_ARG: &'static str = concat!("--length=", stringify!($size));
static EXPECTED_FILE: &'static str = concat!(stringify!($id), ".expected");
static CHECK_FILE: &'static str = concat!(stringify!($id), ".checkfile");
static INPUT_FILE: &'static str = "input.txt";
#[test]
fn test_single_file() {
let ts = TestScenario::new(util_name!());
assert_eq!(
ts.fixtures.read(EXPECTED_FILE),
get_hash!(
ts.ucmd()
.arg(LENGTH_ARG)
.arg(INPUT_FILE)
.succeeds()
.no_stderr()
.stdout_str()
)
);
}
#[test]
fn test_stdin() {
let ts = TestScenario::new(util_name!());
assert_eq!(
ts.fixtures.read(EXPECTED_FILE),
get_hash!(
ts.ucmd()
.arg(LENGTH_ARG)
.pipe_in_fixture(INPUT_FILE)
.succeeds()
.no_stderr()
.stdout_str()
)
);
}
#[test]
fn test_check() {
let ts = TestScenario::new(util_name!());
println!("File content='{}'", ts.fixtures.read(INPUT_FILE));
println!("Check file='{}'", ts.fixtures.read(CHECK_FILE));
ts.ucmd()
.args(&[LENGTH_ARG, "--check", CHECK_FILE])
.succeeds()
.no_stderr()
.stdout_is("input.txt: OK\n");
}
#[test]
fn test_zero() {
let ts = TestScenario::new(util_name!());
assert_eq!(
ts.fixtures.read(EXPECTED_FILE),
get_hash!(
ts.ucmd()
.arg(LENGTH_ARG)
.arg("--zero")
.arg(INPUT_FILE)
.succeeds()
.no_stderr()
.stdout_str()
)
);
}
#[test]
fn test_missing_file() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
at.write("a", "file1\n");
at.write("c", "file3\n");
ts.ucmd()
.args(&[LENGTH_ARG, "a", "b", "c"])
.fails()
.stdout_contains("a\n")
.stdout_contains("c\n")
.stderr_contains("b: No such file or directory");
}
}
};
}
test_digest_with_len! {b2sum, 512}
#[test]
fn test_check_b2sum_length_option_0() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.write("testf", "foobar\n");
at.write("testf.b2sum", "9e2bf63e933e610efee4a8d6cd4a9387e80860edee97e27db3b37a828d226ab1eb92a9cdd8ca9ca67a753edaf8bd89a0558496f67a30af6f766943839acf0110 testf\n");
scene
.ccmd("b2sum")
.arg("--length=0")
.arg("-c")
.arg(at.subdir.join("testf.b2sum"))
.succeeds()
.stdout_only("testf: OK\n");
}
#[test]
fn test_check_b2sum_length_duplicate() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.write("testf", "foobar\n");
scene
.ccmd("b2sum")
.arg("--length=123")
.arg("--length=128")
.arg("testf")
.succeeds()
.stdout_contains("d6d45901dec53e65d2b55fb6e2ab67b0");
}
#[test]
fn test_check_b2sum_length_option_8() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.write("testf", "foobar\n");
at.write("testf.b2sum", "6a testf\n");
scene
.ccmd("b2sum")
.arg("--length=8")
.arg("-c")
.arg(at.subdir.join("testf.b2sum"))
.succeeds()
.stdout_only("testf: OK\n");
}
#[test]
fn test_invalid_b2sum_length_option_not_multiple_of_8() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.write("testf", "foobar\n");
scene
.ccmd("b2sum")
.arg("--length=9")
.arg(at.subdir.join("testf"))
.fails_with_code(1)
.stderr_contains("b2sum: invalid length: '9'")
.stderr_contains("b2sum: length is not a multiple of 8");
}
#[rstest]
#[case("513")]
#[case("1024")]
#[case("18446744073709552000")]
fn test_invalid_b2sum_length_option_too_large(#[case] len: &str) {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.write("testf", "foobar\n");
scene
.ccmd("b2sum")
.arg("--length")
.arg(len)
.arg(at.subdir.join("testf"))
.fails_with_code(1)
.no_stdout()
.stderr_contains(format!("b2sum: invalid length: '{len}'"))
.stderr_contains("b2sum: maximum digest length for 'BLAKE2b' is 512 bits");
}
#[test]
fn test_check_b2sum_tag_output() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("f");
scene
.ccmd("b2sum")
.arg("--length=0")
.arg("--tag")
.arg("f")
.succeeds()
.stdout_only("BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n");
scene
.ccmd("b2sum")
.arg("--length=128")
.arg("--tag")
.arg("f")
.succeeds()
.stdout_only("BLAKE2b-128 (f) = cae66941d9efbd404e4d88758ea67670\n");
}
#[test]
fn test_check_b2sum_verify() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.write("a", "a\n");
scene
.ccmd("b2sum")
.arg("--tag")
.arg("a")
.succeeds()
.stdout_only("BLAKE2b (a) = bedfbb90d858c2d67b7ee8f7523be3d3b54004ef9e4f02f2ad79a1d05bfdfe49b81e3c92ebf99b504102b6bf003fa342587f5b3124c205f55204e8c4b4ce7d7c\n");
scene
.ccmd("b2sum")
.arg("--tag")
.arg("-l")
.arg("128")
.arg("a")
.succeeds()
.stdout_only("BLAKE2b-128 (a) = b93e0fc7bb21633c08bba07c5e71dc00\n");
}
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails_with_code(1);
}
#[test]
fn test_check_b2sum_strict_check() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("f");
let checksums = [
"2e f\n",
"e4a6a0577479b2b4 f\n",
"cae66941d9efbd404e4d88758ea67670 f\n",
"246c0442cd564aced8145b8b60f1370aa7 f\n",
"0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8 f\n",
"4ded8c5fc8b12f3273f877ca585a44ad6503249a2b345d6d9c0e67d85bcb700db4178c0303e93b8f4ad758b8e2c9fd8b3d0c28e585f1928334bb77d36782e8 f\n",
"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce f\n",
];
at.write("ck", &checksums.join(""));
let output = "f: OK\n".to_string().repeat(checksums.len());
scene
.ccmd("b2sum")
.arg("-c")
.arg(at.subdir.join("ck"))
.succeeds()
.stdout_only(&output);
scene
.ccmd("b2sum")
.arg("--strict")
.arg("-c")
.arg(at.subdir.join("ck"))
.succeeds()
.stdout_only(&output);
}
#[test]
fn test_help_shows_correct_utility_name() {
// Test that help output shows the actual utility name instead of "hashsum"
let scene = TestScenario::new(util_name!());
// Test b2sum
scene
.ccmd("b2sum")
.arg("--help")
.succeeds()
.stdout_contains("Usage: b2sum")
.stdout_does_not_contain("Usage: hashsum");
}
+10 -1
View File
@@ -214,7 +214,6 @@ test_digest_with_len! {sha3_224, sha3, 224}
test_digest_with_len! {sha3_256, sha3, 256}
test_digest_with_len! {sha3_384, sha3, 384}
test_digest_with_len! {sha3_512, sha3, 512}
test_digest_with_len! {b2sum, b2sum, 512}
#[test]
fn test_check_sha1() {
@@ -271,6 +270,7 @@ fn test_check_md5_ignore_missing() {
.stderr_contains("the --ignore-missing option is meaningful only when verifying checksums");
}
#[ignore = "moved to standalone"]
#[test]
fn test_check_b2sum_length_option_0() {
let scene = TestScenario::new(util_name!());
@@ -288,6 +288,7 @@ fn test_check_b2sum_length_option_0() {
.stdout_only("testf: OK\n");
}
#[ignore = "moved to standalone"]
#[test]
fn test_check_b2sum_length_duplicate() {
let scene = TestScenario::new(util_name!());
@@ -304,6 +305,7 @@ fn test_check_b2sum_length_duplicate() {
.stdout_contains("d6d45901dec53e65d2b55fb6e2ab67b0");
}
#[ignore = "moved to standalone"]
#[test]
fn test_check_b2sum_length_option_8() {
let scene = TestScenario::new(util_name!());
@@ -321,6 +323,7 @@ fn test_check_b2sum_length_option_8() {
.stdout_only("testf: OK\n");
}
#[ignore = "moved to standalone"]
#[test]
fn test_invalid_b2sum_length_option_not_multiple_of_8() {
let scene = TestScenario::new(util_name!());
@@ -338,8 +341,11 @@ fn test_invalid_b2sum_length_option_not_multiple_of_8() {
}
#[rstest]
#[ignore = "moved to standalone"]
#[case("513")]
#[ignore = "moved to standalone"]
#[case("1024")]
#[ignore = "moved to standalone"]
#[case("18446744073709552000")]
fn test_invalid_b2sum_length_option_too_large(#[case] len: &str) {
let scene = TestScenario::new(util_name!());
@@ -358,6 +364,7 @@ fn test_invalid_b2sum_length_option_too_large(#[case] len: &str) {
.stderr_contains("b2sum: maximum digest length for 'BLAKE2b' is 512 bits");
}
#[ignore = "moved to standalone"]
#[test]
fn test_check_b2sum_tag_output() {
let scene = TestScenario::new(util_name!());
@@ -382,6 +389,7 @@ fn test_check_b2sum_tag_output() {
.stdout_only("BLAKE2b-128 (f) = cae66941d9efbd404e4d88758ea67670\n");
}
#[ignore = "moved to standalone"]
#[test]
fn test_check_b2sum_verify() {
let scene = TestScenario::new(util_name!());
@@ -1068,6 +1076,7 @@ fn test_star_to_start() {
.stdout_only("f: OK\n");
}
#[ignore = "moved to standalone"]
#[test]
fn test_check_b2sum_strict_check() {
let scene = TestScenario::new(util_name!());
+1
View File
@@ -0,0 +1 @@
hello, world
+4
View File
@@ -68,6 +68,10 @@ mod test_cksum;
#[path = "by-util/test_comm.rs"]
mod test_comm;
#[cfg(feature = "b2sum")]
#[path = "by-util/test_b2sum.rs"]
mod test_b2sum;
#[cfg(feature = "md5sum")]
#[path = "by-util/test_md5sum.rs"]
mod test_md5sum;