mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
introduce checksum_common
This commit is contained in:
Generated
+11
@@ -3239,6 +3239,17 @@ dependencies = [
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_checksum_common"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codspeed-divan-compat",
|
||||
"fluent",
|
||||
"tempfile",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_chgrp"
|
||||
version = "0.6.0"
|
||||
|
||||
@@ -407,6 +407,7 @@ uucore = { version = "0.6.0", package = "uucore", path = "src/uucore" }
|
||||
uucore_procs = { version = "0.6.0", package = "uucore_procs", path = "src/uucore_procs" }
|
||||
uu_ls = { version = "0.6.0", path = "src/uu/ls" }
|
||||
uu_base32 = { version = "0.6.0", path = "src/uu/base32" }
|
||||
uu_checksum_common = { version = "0.6.0", path = "src/uu/checksum_common" }
|
||||
uutests = { version = "0.6.0", package = "uutests", path = "tests/uutests" }
|
||||
|
||||
[dependencies]
|
||||
|
||||
Generated
+10
@@ -1692,12 +1692,22 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uu_checksum_common"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fluent",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_cksum"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fluent",
|
||||
"uu_checksum_common",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
[package]
|
||||
name = "uu_checksum_common"
|
||||
description = "Base for checksum utils"
|
||||
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/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"checksum",
|
||||
"encoding",
|
||||
"sum",
|
||||
"hardware",
|
||||
] }
|
||||
fluent = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
divan = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
# [[bench]]
|
||||
# name = "b2sum_bench"
|
||||
# harness = false
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../LICENSE
|
||||
@@ -0,0 +1,19 @@
|
||||
ck-common-after-help = With no FILE or when FILE is -, read standard input
|
||||
|
||||
# checksum argument help messages
|
||||
ck-common-help-algorithm = select the digest type to use. See DIGEST below
|
||||
ck-common-help-untagged = create a reversed style checksum, without digest type
|
||||
ck-common-help-tag-default = create a BSD style checksum (default)
|
||||
ck-common-help-tag = create a BSD style checksum
|
||||
ck-common-help-text = read in text mode (default)
|
||||
ck-common-help-length = digest length in bits; must not exceed the max size and must be a multiple of 8 for blake2b; must be 224, 256, 384, or 512 for sha2 or sha3
|
||||
ck-common-help-check = read checksums from the FILEs and check them
|
||||
ck-common-help-base64 = emit base64-encoded digests, not hexadecimal
|
||||
ck-common-help-raw = emit a raw binary digest, not hexadecimal
|
||||
ck-common-help-zero = end each output line with NUL, not newline, and disable file name escaping
|
||||
ck-common-help-strict = exit non-zero for improperly formatted checksum lines
|
||||
ck-common-help-warn = warn about improperly formatted checksum lines
|
||||
ck-common-help-status = don't output anything, status code shows success
|
||||
ck-common-help-quiet = don't print OK for each successfully verified file
|
||||
ck-common-help-ignore-missing = don't fail or report status for missing files
|
||||
ck-common-help-debug = print CPU hardware capability detection info used by cksum
|
||||
@@ -0,0 +1,19 @@
|
||||
ck-common-after-help = Sans FICHIER ou quand FICHER est -, lit l'entrée standard
|
||||
|
||||
# Messages d'aide d'arguments checksum
|
||||
ck-common-help-algorithm = sélectionner le type de condensé à utiliser. Voir DIGEST ci-dessous
|
||||
ck-common-help-untagged = créer une somme de contrôle de style inversé, sans type de condensé
|
||||
ck-common-help-tag-default = créer une somme de contrôle de style BSD (par défaut)
|
||||
ck-common-help-tag = créer une somme de contrôle de style BSD
|
||||
ck-common-help-text = lire en mode texte (par défaut)
|
||||
ck-common-help-length = longueur du condensé en bits ; ne doit pas dépasser le maximum pour l'algorithme blake2 et doit être un multiple de 8
|
||||
ck-common-help-raw = émettre un condensé binaire brut, pas hexadécimal
|
||||
ck-common-help-strict = sortir avec un code non-zéro pour les lignes de somme de contrôle mal formatées
|
||||
ck-common-help-check = lire les sommes de hachage des FICHIERs et les vérifier
|
||||
ck-common-help-base64 = émettre un condensé base64, pas hexadécimal
|
||||
ck-common-help-warn = avertir des lignes de somme de contrôle mal formatées
|
||||
ck-common-help-status = ne rien afficher, le code de statut indique le succès
|
||||
ck-common-help-quiet = ne pas afficher OK pour chaque fichier vérifié avec succès
|
||||
ck-common-help-ignore-missing = ne pas échouer ou signaler le statut pour les fichiers manquants
|
||||
ck-common-help-zero = terminer chaque ligne de sortie avec NUL, pas un saut de ligne, et désactiver l'échappement des noms de fichiers
|
||||
ck-common-help-debug = afficher les informations de débogage sur la détection de la prise en charge matérielle du processeur
|
||||
@@ -0,0 +1,215 @@
|
||||
// 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 clap::{Arg, ArgAction, Command};
|
||||
use uucore::{checksum::SUPPORTED_ALGORITHMS, translate};
|
||||
|
||||
/// List of all options that can be encountered in checksum utils
|
||||
pub mod options {
|
||||
// cksum-specific
|
||||
pub const ALGORITHM: &str = "algorithm";
|
||||
pub const DEBUG: &str = "debug";
|
||||
|
||||
// positional arg
|
||||
pub const FILE: &str = "file";
|
||||
|
||||
pub const UNTAGGED: &str = "untagged";
|
||||
pub const TAG: &str = "tag";
|
||||
pub const LENGTH: &str = "length";
|
||||
pub const RAW: &str = "raw";
|
||||
pub const BASE64: &str = "base64";
|
||||
pub const CHECK: &str = "check";
|
||||
pub const TEXT: &str = "text";
|
||||
pub const BINARY: &str = "binary";
|
||||
pub const ZERO: &str = "zero";
|
||||
|
||||
// check-specific
|
||||
pub const STRICT: &str = "strict";
|
||||
pub const STATUS: &str = "status";
|
||||
pub const WARN: &str = "warn";
|
||||
pub const IGNORE_MISSING: &str = "ignore-missing";
|
||||
pub const QUIET: &str = "quiet";
|
||||
}
|
||||
|
||||
/// `ChecksumCommand` is a convenience trait to more easily declare checksum
|
||||
/// CLI interfaces with
|
||||
pub trait ChecksumCommand {
|
||||
fn with_algo(self) -> Self;
|
||||
|
||||
fn with_length(self) -> Self;
|
||||
|
||||
fn with_check_and_opts(self) -> Self;
|
||||
|
||||
fn with_binary(self) -> Self;
|
||||
|
||||
fn with_text(self, is_default: bool) -> Self;
|
||||
|
||||
fn with_tag(self, is_default: bool) -> Self;
|
||||
|
||||
fn with_untagged(self) -> Self;
|
||||
|
||||
fn with_raw(self) -> Self;
|
||||
|
||||
fn with_base64(self) -> Self;
|
||||
|
||||
fn with_zero(self) -> Self;
|
||||
|
||||
fn with_debug(self) -> Self;
|
||||
}
|
||||
|
||||
impl ChecksumCommand for Command {
|
||||
fn with_algo(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::ALGORITHM)
|
||||
.long(options::ALGORITHM)
|
||||
.short('a')
|
||||
.help(translate!("ck-common-help-algorithm"))
|
||||
.value_name("ALGORITHM")
|
||||
.value_parser(SUPPORTED_ALGORITHMS),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_length(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::LENGTH)
|
||||
.long(options::LENGTH)
|
||||
.short('l')
|
||||
.help(translate!("ck-common-help-length"))
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_check_and_opts(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::CHECK)
|
||||
.short('c')
|
||||
.long(options::CHECK)
|
||||
.help(translate!("ck-common-help-check"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::WARN)
|
||||
.short('w')
|
||||
.long("warn")
|
||||
.help(translate!("ck-common-help-warn"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::STATUS, options::QUIET]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STATUS)
|
||||
.long("status")
|
||||
.help(translate!("ck-common-help-status"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::WARN, options::QUIET]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::QUIET)
|
||||
.long(options::QUIET)
|
||||
.help(translate!("ck-common-help-quiet"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::STATUS, options::WARN]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::IGNORE_MISSING)
|
||||
.long(options::IGNORE_MISSING)
|
||||
.help(translate!("ck-common-help-ignore-missing"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STRICT)
|
||||
.long(options::STRICT)
|
||||
.help(translate!("ck-common-help-strict"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_binary(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::BINARY)
|
||||
.long(options::BINARY)
|
||||
.short('b')
|
||||
.hide(true)
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_text(self, is_default: bool) -> Self {
|
||||
let mut arg = Arg::new(options::TEXT)
|
||||
.long(options::TEXT)
|
||||
.short('t')
|
||||
.action(ArgAction::SetTrue);
|
||||
|
||||
arg = if is_default {
|
||||
arg.help(translate!("ck-common-help-text"))
|
||||
} else {
|
||||
arg.hide(true)
|
||||
};
|
||||
|
||||
self.arg(arg)
|
||||
}
|
||||
|
||||
fn with_tag(self, default: bool) -> Self {
|
||||
let mut arg = Arg::new(options::TAG)
|
||||
.long(options::TAG)
|
||||
.action(ArgAction::SetTrue);
|
||||
|
||||
arg = if default {
|
||||
arg.help(translate!("ck-common-help-tag-default"))
|
||||
} else {
|
||||
arg.help(translate!("ck-common-help-tag"))
|
||||
};
|
||||
|
||||
self.arg(arg)
|
||||
}
|
||||
|
||||
fn with_untagged(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::UNTAGGED)
|
||||
.long(options::UNTAGGED)
|
||||
.help(translate!("ck-common-help-untagged"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_raw(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::RAW)
|
||||
.long(options::RAW)
|
||||
.help(translate!("ck-common-help-raw"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_base64(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::BASE64)
|
||||
.long(options::BASE64)
|
||||
.help(translate!("ck-common-help-base64"))
|
||||
.action(ArgAction::SetTrue)
|
||||
// Even though this could easily just override an earlier '--raw',
|
||||
// GNU cksum does not permit these flags to be combined:
|
||||
.conflicts_with(options::RAW),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_zero(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::ZERO)
|
||||
.long(options::ZERO)
|
||||
.short('z')
|
||||
.help(translate!("ck-common-help-zero"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_debug(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::DEBUG)
|
||||
.long(options::DEBUG)
|
||||
.help(translate!("ck-common-help-debug"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
// 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 std::ffi::OsString;
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint};
|
||||
|
||||
use uucore::checksum::compute::{
|
||||
ChecksumComputeOptions, OutputFormat, perform_checksum_computation,
|
||||
};
|
||||
use uucore::checksum::validate::{self, ChecksumValidateOptions, ChecksumVerbose};
|
||||
use uucore::checksum::{AlgoKind, ChecksumError, SizedAlgoKind};
|
||||
use uucore::error::UResult;
|
||||
use uucore::line_ending::LineEnding;
|
||||
use uucore::{crate_version, format_usage, localized_help_template, util_name};
|
||||
|
||||
mod cli;
|
||||
pub use cli::ChecksumCommand;
|
||||
pub use cli::options;
|
||||
|
||||
/// Expands to generate the right `uumain` and `uu_app` functions
|
||||
/// for standalone checksum binaries.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// use uu_checksum_common::declare_standalone;
|
||||
/// use uucore::checksum::AlgoKind;
|
||||
///
|
||||
/// declare_standalone!("sha512sum", AlgoKind::Sha512);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! declare_standalone {
|
||||
($bin:literal, $kind:expr) => {
|
||||
#[::uucore::main]
|
||||
pub fn uumain(args: impl ::uucore::Args) -> ::uucore::error::UResult<()> {
|
||||
::uu_checksum_common::standalone_main($kind, uu_app(), args)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn uu_app() -> ::clap::Command {
|
||||
::uu_checksum_common::standalone_checksum_app(
|
||||
::uucore::translate!(concat!($bin, "-about")),
|
||||
::uucore::translate!(concat!($bin, "-usage")),
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Entrypoint for standalone checksums accepting the `--length` argument
|
||||
///
|
||||
/// Note: Ideally, we wouldn't require a `cmd` to be passed to the function,
|
||||
/// but for localization purposes, the standalone binaries must declare their
|
||||
/// command (with about and usage) themselves, otherwise calling --help from
|
||||
/// the multicall binary results in an unformatted output.
|
||||
pub fn standalone_with_length_main(
|
||||
algo: AlgoKind,
|
||||
cmd: Command,
|
||||
args: impl uucore::Args,
|
||||
validate_len: fn(&str) -> UResult<Option<usize>>,
|
||||
) -> UResult<()> {
|
||||
let matches = uucore::clap_localization::handle_clap_result(cmd, args)?;
|
||||
let algo = Some(algo);
|
||||
|
||||
let length = matches
|
||||
.get_one::<String>(options::LENGTH)
|
||||
.map(String::as_str)
|
||||
.map(validate_len)
|
||||
.transpose()?
|
||||
.flatten();
|
||||
|
||||
let format = OutputFormat::from_standalone(std::env::args_os());
|
||||
|
||||
checksum_main(algo, length, matches, format?)
|
||||
}
|
||||
|
||||
/// Entrypoint for standalone checksums *NOT* accepting the `--length` argument
|
||||
pub fn standalone_main(algo: AlgoKind, cmd: Command, args: impl uucore::Args) -> UResult<()> {
|
||||
let matches = uucore::clap_localization::handle_clap_result(cmd, args)?;
|
||||
let algo = Some(algo);
|
||||
|
||||
let format = OutputFormat::from_standalone(std::env::args_os());
|
||||
|
||||
checksum_main(algo, None, matches, format?)
|
||||
}
|
||||
|
||||
/// Base command processing for all the checksum executables.
|
||||
pub fn default_checksum_app(about: String, usage: String) -> Command {
|
||||
Command::new(util_name())
|
||||
.version(crate_version!())
|
||||
.help_template(localized_help_template(util_name()))
|
||||
.about(about)
|
||||
.override_usage(format_usage(&usage))
|
||||
.infer_long_args(true)
|
||||
.args_override_self(true)
|
||||
.arg(
|
||||
Arg::new(options::FILE)
|
||||
.hide(true)
|
||||
.action(ArgAction::Append)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.default_value("-")
|
||||
.hide_default_value(true)
|
||||
.value_hint(ValueHint::FilePath),
|
||||
)
|
||||
}
|
||||
|
||||
/// Command processing for standalone checksums accepting the `--length`
|
||||
/// argument
|
||||
pub fn standalone_checksum_app_with_length(about: String, usage: String) -> Command {
|
||||
default_checksum_app(about, usage)
|
||||
.with_binary()
|
||||
.with_check_and_opts()
|
||||
.with_length()
|
||||
.with_tag(false)
|
||||
.with_text(true)
|
||||
.with_zero()
|
||||
}
|
||||
|
||||
/// Command processing for standalone checksums *NOT* accepting the `--length`
|
||||
/// argument
|
||||
pub fn standalone_checksum_app(about: String, usage: String) -> Command {
|
||||
default_checksum_app(about, usage)
|
||||
.with_binary()
|
||||
.with_check_and_opts()
|
||||
.with_tag(false)
|
||||
.with_text(true)
|
||||
.with_zero()
|
||||
}
|
||||
|
||||
/// This is the common entrypoint to all checksum utils. Performs some
|
||||
/// validation on arguments and proceeds in computing or checking mode.
|
||||
pub fn checksum_main(
|
||||
algo: Option<AlgoKind>,
|
||||
length: Option<usize>,
|
||||
matches: ArgMatches,
|
||||
output_format: OutputFormat,
|
||||
) -> UResult<()> {
|
||||
let check = matches.get_flag("check");
|
||||
|
||||
let check_flag = |flag| match (check, matches.get_flag(flag)) {
|
||||
(_, false) => Ok(false),
|
||||
(true, true) => Ok(true),
|
||||
(false, true) => Err(ChecksumError::CheckOnlyFlag(flag.into())),
|
||||
};
|
||||
|
||||
// Each of the following flags are only expected in --check mode.
|
||||
// If we encounter them otherwise, end with an error.
|
||||
let ignore_missing = check_flag("ignore-missing")?;
|
||||
let warn = check_flag("warn")?;
|
||||
let quiet = check_flag("quiet")?;
|
||||
let strict = check_flag("strict")?;
|
||||
let status = check_flag("status")?;
|
||||
|
||||
// clap provides the default value -. So we unwrap() safety.
|
||||
let files = matches
|
||||
.get_many::<OsString>(options::FILE)
|
||||
.unwrap()
|
||||
.map(|s| s.as_os_str());
|
||||
|
||||
if check {
|
||||
// cksum does not support '--check'ing legacy algorithms
|
||||
if algo.is_some_and(AlgoKind::is_legacy) {
|
||||
return Err(ChecksumError::AlgorithmNotSupportedWithCheck.into());
|
||||
}
|
||||
|
||||
let text_flag = matches.get_flag(options::TEXT);
|
||||
let binary_flag = matches.get_flag(options::BINARY);
|
||||
let tag = matches.get_flag(options::TAG);
|
||||
|
||||
if tag || binary_flag || text_flag {
|
||||
return Err(ChecksumError::BinaryTextConflict.into());
|
||||
}
|
||||
|
||||
// Execute the checksum validation based on the presence of files or the use of stdin
|
||||
|
||||
let verbose = ChecksumVerbose::new(status, quiet, warn);
|
||||
let opts = ChecksumValidateOptions {
|
||||
ignore_missing,
|
||||
strict,
|
||||
verbose,
|
||||
};
|
||||
|
||||
return validate::perform_checksum_validation(files, algo, length, opts);
|
||||
}
|
||||
|
||||
// Not --check
|
||||
|
||||
// Set the default algorithm to CRC when not '--check'ing.
|
||||
let algo_kind = algo.unwrap_or(AlgoKind::Crc);
|
||||
|
||||
let algo = SizedAlgoKind::from_unsized(algo_kind, length)?;
|
||||
let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::ZERO));
|
||||
|
||||
let opts = ChecksumComputeOptions {
|
||||
algo_kind: algo,
|
||||
output_format,
|
||||
line_ending,
|
||||
};
|
||||
|
||||
perform_checksum_computation(opts, files)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user