forked from extern/nushell
Improve md5 and sha256 code (#3841)
* Refactor Hash code to simplify md5 and sha256 implementations Md5 and Sha256 (and other future digests) require less boilerplate code now. Error reporting includues the name of the hash again. * Add missing hash sha256 test
This commit is contained in:
parent
7f7af2bbaa
commit
9696e4d315
@ -1,40 +1,84 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::ShellTypeName;
|
||||
use nu_protocol::{ColumnPath, Primitive, UntaggedValue, Value};
|
||||
use nu_protocol::{ColumnPath, Primitive, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{ShellTypeName, Signature};
|
||||
use nu_source::Tag;
|
||||
|
||||
pub fn run<D>(args: CommandArgs) -> Result<OutputStream, ShellError>
|
||||
pub trait HashDigest: digest::Digest {
|
||||
fn name() -> &'static str;
|
||||
fn examples() -> Vec<Example>;
|
||||
}
|
||||
|
||||
pub struct SubCommand<D: HashDigest> {
|
||||
name_string: String,
|
||||
usage_string: String,
|
||||
phantom: PhantomData<D>,
|
||||
}
|
||||
|
||||
impl<D: HashDigest> Default for SubCommand<D> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name_string: format!("hash {}", D::name()),
|
||||
usage_string: format!("{} encode a value", D::name()),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> WholeStreamCommand for SubCommand<D>
|
||||
where
|
||||
D: digest::Digest,
|
||||
D: HashDigest + Send + Sync,
|
||||
digest::Output<D>: core::fmt::LowerHex,
|
||||
{
|
||||
let column_paths: Vec<ColumnPath> = args.rest(0)?;
|
||||
fn name(&self) -> &str {
|
||||
&self.name_string
|
||||
}
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
action::<D>(&v, v.tag())
|
||||
} else {
|
||||
let mut ret = v;
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name()).rest(
|
||||
SyntaxShape::ColumnPath,
|
||||
format!("optionally {} encode data by column paths", D::name()),
|
||||
)
|
||||
}
|
||||
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action::<D>(old, old.tag())),
|
||||
)?;
|
||||
fn usage(&self) -> &str {
|
||||
&self.usage_string
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
D::examples()
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let column_paths: Vec<ColumnPath> = args.rest(0)?;
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
action::<D>(&v, v.tag())
|
||||
} else {
|
||||
let mut ret = v;
|
||||
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action::<D>(old, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
})
|
||||
.into_input_stream())
|
||||
})
|
||||
.into_input_stream())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn action<D>(input: &Value, tag: Tag) -> Result<Value, ShellError>
|
||||
where
|
||||
D: digest::Digest,
|
||||
D: HashDigest,
|
||||
digest::Output<D>: core::fmt::LowerHex,
|
||||
{
|
||||
match &input.value {
|
||||
@ -49,7 +93,7 @@ where
|
||||
other => {
|
||||
let got = format!("got {}", other.type_name());
|
||||
Err(ShellError::labeled_error(
|
||||
"value is not supported for hashing",
|
||||
format!("value is not supported for hashing as {}", D::name()),
|
||||
got,
|
||||
tag.span,
|
||||
))
|
||||
|
@ -1,34 +1,17 @@
|
||||
use crate::prelude::*;
|
||||
use md5::Md5;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_protocol::UntaggedValue;
|
||||
|
||||
use super::generic_digest;
|
||||
use super::generic_digest::{self, HashDigest};
|
||||
|
||||
pub struct SubCommand;
|
||||
pub type SubCommand = generic_digest::SubCommand<Md5>;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"hash md5"
|
||||
impl HashDigest for Md5 {
|
||||
fn name() -> &'static str {
|
||||
"md5"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("hash md5").rest(
|
||||
SyntaxShape::ColumnPath,
|
||||
"optionally md5 encode data by column paths",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"md5 encode a value"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
generic_digest::run::<Md5>(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
fn examples() -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "md5 encode a string",
|
||||
|
@ -1,34 +1,17 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_protocol::UntaggedValue;
|
||||
use sha2::Sha256;
|
||||
|
||||
use super::generic_digest;
|
||||
use super::generic_digest::{self, HashDigest};
|
||||
|
||||
pub struct SubCommand;
|
||||
pub type SubCommand = generic_digest::SubCommand<Sha256>;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"hash sha256"
|
||||
impl HashDigest for Sha256 {
|
||||
fn name() -> &'static str {
|
||||
"sha256"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("hash sha256").rest(
|
||||
SyntaxShape::ColumnPath,
|
||||
"optionally sha256 encode data by column paths",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"sha256 encode a value"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
generic_digest::run::<Sha256>(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
fn examples() -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "sha256 encode a string",
|
||||
|
@ -84,8 +84,8 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
// Text manipulation
|
||||
whole_stream_command(Hash),
|
||||
whole_stream_command(HashBase64),
|
||||
whole_stream_command(HashMd5),
|
||||
whole_stream_command(HashSha256),
|
||||
whole_stream_command(HashMd5::default()),
|
||||
whole_stream_command(HashSha256::default()),
|
||||
whole_stream_command(Split),
|
||||
whole_stream_command(SplitColumn),
|
||||
whole_stream_command(SplitRow),
|
||||
|
@ -96,3 +96,19 @@ fn md5_works_with_file() {
|
||||
|
||||
assert_eq!(actual.out, "4de97601d232c427977ef11db396c951");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha256_works_with_file() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
open sample.db | hash sha256
|
||||
"#
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
actual.out,
|
||||
"2f5050e7eea415c1f3d80b5d93355efd15043ec9157a2bb167a9e73f2ae651f2"
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user