diff options
Diffstat (limited to 'vendor/gix-actor')
-rw-r--r-- | vendor/gix-actor/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/gix-actor/Cargo.toml | 81 | ||||
-rw-r--r-- | vendor/gix-actor/src/lib.rs | 45 | ||||
-rw-r--r-- | vendor/gix-actor/src/signature/decode.rs | 159 | ||||
-rw-r--r-- | vendor/gix-actor/src/signature/mod.rs | 136 |
5 files changed, 422 insertions, 0 deletions
diff --git a/vendor/gix-actor/.cargo-checksum.json b/vendor/gix-actor/.cargo-checksum.json new file mode 100644 index 000000000..722a61e21 --- /dev/null +++ b/vendor/gix-actor/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"09f0d7585b773608c4209e13eb877201036010f9d005789fc35e49f7655ac940","src/lib.rs":"b5de3d3c223fa9423386353b077ac179d6a27358d14b04b0be625f46b1f16794","src/signature/decode.rs":"68d44b6c899dc19da3d7a327b26fc50bfe612a7c34216fb51ae52e8e72247e67","src/signature/mod.rs":"861191a680568abeaa79d9989f01eb249cad1e360a8824464cf8974502d929a8"},"package":"dc22b0cdc52237667c301dd7cdc6ead8f8f73c9f824e9942c8ebd6b764f6c0bf"}
\ No newline at end of file diff --git a/vendor/gix-actor/Cargo.toml b/vendor/gix-actor/Cargo.toml new file mode 100644 index 000000000..b4585ce58 --- /dev/null +++ b/vendor/gix-actor/Cargo.toml @@ -0,0 +1,81 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.64" +name = "gix-actor" +version = "0.19.0" +authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"] +include = ["src/**/*"] +description = "A way to identify git actors" +license = "MIT/Apache-2.0" +repository = "https://github.com/Byron/gitoxide" + +[package.metadata.docs.rs] +all-features = true +features = ["document-features"] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[lib] +doctest = false + +[dependencies.bstr] +version = "1.3.0" +features = [ + "std", + "unicode", +] +default-features = false + +[dependencies.btoi] +version = "0.4.2" + +[dependencies.document-features] +version = "0.2.0" +optional = true + +[dependencies.gix-date] +version = "^0.4.3" + +[dependencies.gix-features] +version = "^0.28.0" +optional = true + +[dependencies.itoa] +version = "1.0.1" + +[dependencies.nom] +version = "7" +features = ["std"] +default-features = false + +[dependencies.serde] +version = "1.0.114" +features = ["derive"] +optional = true +default-features = false + +[dependencies.thiserror] +version = "1.0.38" + +[dev-dependencies.pretty_assertions] +version = "1.0.0" + +[features] +serde1 = [ + "serde", + "bstr/serde", + "gix-date/serde1", +] diff --git a/vendor/gix-actor/src/lib.rs b/vendor/gix-actor/src/lib.rs new file mode 100644 index 000000000..182f0beee --- /dev/null +++ b/vendor/gix-actor/src/lib.rs @@ -0,0 +1,45 @@ +//! This crate provides ways of identifying an actor within the git repository both in shared/mutable and mutable variants. +//! +//! ## Feature Flags +#![cfg_attr( + feature = "document-features", + cfg_attr(doc, doc = ::document_features::document_features!()) +)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![deny(missing_docs, rust_2018_idioms)] +#![forbid(unsafe_code)] + +use bstr::{BStr, BString}; +pub use gix_date::{time::Sign, Time}; + +/// +pub mod signature; + +/// A mutable signature is created by an actor at a certain time. +/// +/// Note that this is not a cryptographical signature. +#[derive(Default, PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +pub struct Signature { + /// The actors name. + pub name: BString, + /// The actor's email. + pub email: BString, + /// The time stamp at which the signature is performed. + pub time: Time, +} + +/// A immutable signature is created by an actor at a certain time. +/// +/// Note that this is not a cryptographical signature. +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy, Default)] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +pub struct SignatureRef<'a> { + /// The actor's name. + #[cfg_attr(feature = "serde1", serde(borrow))] + pub name: &'a BStr, + /// The actor's email. + pub email: &'a BStr, + /// The time stamp at which the signature was performed. + pub time: gix_date::Time, +} diff --git a/vendor/gix-actor/src/signature/decode.rs b/vendor/gix-actor/src/signature/decode.rs new file mode 100644 index 000000000..5483d1651 --- /dev/null +++ b/vendor/gix-actor/src/signature/decode.rs @@ -0,0 +1,159 @@ +use bstr::ByteSlice; +use btoi::btoi; +use nom::{ + branch::alt, + bytes::complete::{tag, take, take_until, take_while_m_n}, + character::is_digit, + error::{context, ContextError, ParseError}, + sequence::{terminated, tuple}, + IResult, +}; + +use crate::{Sign, SignatureRef, Time}; + +const SPACE: &[u8] = b" "; + +/// Parse a signature from the bytes input `i` using `nom`. +pub fn decode<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + i: &'a [u8], +) -> IResult<&'a [u8], SignatureRef<'a>, E> { + let (i, (name, email, time, tzsign, hours, minutes)) = context( + "<name> <<email>> <timestamp> <+|-><HHMM>", + tuple(( + context("<name>", terminated(take_until(&b" <"[..]), take(2usize))), + context("<email>", terminated(take_until(&b"> "[..]), take(2usize))), + context("<timestamp>", |i| { + terminated(take_until(SPACE), take(1usize))(i).and_then(|(i, v)| { + btoi::<u32>(v) + .map(|v| (i, v)) + .map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes))) + }) + }), + context("+|-", alt((tag(b"-"), tag(b"+")))), + context("HH", |i| { + take_while_m_n(2usize, 2, is_digit)(i).and_then(|(i, v)| { + btoi::<i32>(v) + .map(|v| (i, v)) + .map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes))) + }) + }), + context("MM", |i| { + take_while_m_n(2usize, 2, is_digit)(i).and_then(|(i, v)| { + btoi::<i32>(v) + .map(|v| (i, v)) + .map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes))) + }) + }), + )), + )(i)?; + + debug_assert!(tzsign[0] == b'-' || tzsign[0] == b'+', "parser assure it's +|- only"); + let sign = if tzsign[0] == b'-' { Sign::Minus } else { Sign::Plus }; // + let offset = (hours * 3600 + minutes * 60) * if sign == Sign::Minus { -1 } else { 1 }; + + Ok(( + i, + SignatureRef { + name: name.as_bstr(), + email: email.as_bstr(), + time: Time { + seconds_since_unix_epoch: time, + offset_in_seconds: offset, + sign, + }, + }, + )) +} + +#[cfg(test)] +mod tests { + mod parse_signature { + use bstr::ByteSlice; + use gix_testtools::to_bstr_err; + use nom::IResult; + + use crate::{signature, Sign, SignatureRef, Time}; + + fn decode(i: &[u8]) -> IResult<&[u8], SignatureRef<'_>, nom::error::VerboseError<&[u8]>> { + signature::decode(i) + } + + fn signature( + name: &'static str, + email: &'static str, + time: u32, + sign: Sign, + offset: i32, + ) -> SignatureRef<'static> { + SignatureRef { + name: name.as_bytes().as_bstr(), + email: email.as_bytes().as_bstr(), + time: Time { + seconds_since_unix_epoch: time, + offset_in_seconds: offset, + sign, + }, + } + } + + #[test] + fn tz_minus() { + assert_eq!( + decode(b"Sebastian Thiel <byronimo@gmail.com> 1528473343 -0230") + .expect("parse to work") + .1, + signature("Sebastian Thiel", "byronimo@gmail.com", 1528473343, Sign::Minus, -9000) + ); + } + + #[test] + fn tz_plus() { + assert_eq!( + decode(b"Sebastian Thiel <byronimo@gmail.com> 1528473343 +0230") + .expect("parse to work") + .1, + signature("Sebastian Thiel", "byronimo@gmail.com", 1528473343, Sign::Plus, 9000) + ); + } + + #[test] + fn negative_offset_0000() { + assert_eq!( + decode(b"Sebastian Thiel <byronimo@gmail.com> 1528473343 -0000") + .expect("parse to work") + .1, + signature("Sebastian Thiel", "byronimo@gmail.com", 1528473343, Sign::Minus, 0) + ); + } + + #[test] + fn empty_name_and_email() { + assert_eq!( + decode(b" <> 12345 -1215").expect("parse to work").1, + signature("", "", 12345, Sign::Minus, -44100) + ); + } + + #[test] + fn invalid_signature() { + assert_eq!( + decode(b"hello < 12345 -1215") + .map_err(to_bstr_err) + .expect_err("parse fails as > is missing") + .to_string(), + "Parse error:\nTakeUntil at: 12345 -1215\nin section '<email>', at: 12345 -1215\nin section '<name> <<email>> <timestamp> <+|-><HHMM>', at: hello < 12345 -1215\n" + ); + } + + #[test] + fn invalid_time() { + assert_eq!( + decode(b"hello <> abc -1215") + .map_err(to_bstr_err) + .expect_err("parse fails as > is missing") + .to_string(), + "Parse error:\nMapRes at: -1215\nin section '<timestamp>', at: abc -1215\nin section '<name> <<email>> <timestamp> <+|-><HHMM>', at: hello <> abc -1215\n" + ); + } + } +} diff --git a/vendor/gix-actor/src/signature/mod.rs b/vendor/gix-actor/src/signature/mod.rs new file mode 100644 index 000000000..fa5fb8470 --- /dev/null +++ b/vendor/gix-actor/src/signature/mod.rs @@ -0,0 +1,136 @@ +mod _ref { + use bstr::{BStr, ByteSlice}; + + use crate::{signature::decode, Signature, SignatureRef}; + + impl<'a> SignatureRef<'a> { + /// Deserialize a signature from the given `data`. + pub fn from_bytes<E>(data: &'a [u8]) -> Result<SignatureRef<'a>, nom::Err<E>> + where + E: nom::error::ParseError<&'a [u8]> + nom::error::ContextError<&'a [u8]>, + { + decode(data).map(|(_, t)| t) + } + + /// Create an owned instance from this shared one. + pub fn to_owned(&self) -> Signature { + Signature { + name: self.name.to_owned(), + email: self.email.to_owned(), + time: self.time, + } + } + + /// Trim whitespace surrounding the name and email and return a new signature. + pub fn trim(&self) -> SignatureRef<'a> { + SignatureRef { + name: self.name.trim().as_bstr(), + email: self.email.trim().as_bstr(), + time: self.time, + } + } + + /// Return the actor's name and email, effectively excluding the time stamp of this signature. + pub fn actor(&self) -> (&BStr, &BStr) { + (self.name, self.email) + } + } +} + +mod convert { + use crate::{Signature, SignatureRef}; + + impl Signature { + /// An empty signature, similar to 'null'. + pub fn empty() -> Self { + Signature::default() + } + + /// Borrow this instance as immutable + pub fn to_ref(&self) -> SignatureRef<'_> { + SignatureRef { + name: self.name.as_ref(), + email: self.email.as_ref(), + time: self.time, + } + } + } + + impl From<SignatureRef<'_>> for Signature { + fn from(other: SignatureRef<'_>) -> Signature { + let SignatureRef { name, email, time } = other; + Signature { + name: name.to_owned(), + email: email.to_owned(), + time, + } + } + } + + impl<'a> From<&'a Signature> for SignatureRef<'a> { + fn from(other: &'a Signature) -> SignatureRef<'a> { + other.to_ref() + } + } +} + +mod write { + use std::io; + + use bstr::{BStr, ByteSlice}; + + use crate::{Signature, SignatureRef}; + + /// The Error produced by [`Signature::write_to()`]. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + enum Error { + #[error("Signature name or email must not contain '<', '>' or \\n")] + IllegalCharacter, + } + + impl From<Error> for io::Error { + fn from(err: Error) -> Self { + io::Error::new(io::ErrorKind::Other, err) + } + } + + /// Output + impl Signature { + /// Serialize this instance to `out` in the git serialization format for actors. + pub fn write_to(&self, out: impl io::Write) -> io::Result<()> { + self.to_ref().write_to(out) + } + /// Computes the number of bytes necessary to serialize this signature + pub fn size(&self) -> usize { + self.to_ref().size() + } + } + + impl<'a> SignatureRef<'a> { + /// Serialize this instance to `out` in the git serialization format for actors. + pub fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + out.write_all(validated_token(self.name)?)?; + out.write_all(b" ")?; + out.write_all(b"<")?; + out.write_all(validated_token(self.email)?)?; + out.write_all(b"> ")?; + self.time.write_to(out) + } + /// Computes the number of bytes necessary to serialize this signature + pub fn size(&self) -> usize { + self.name.len() + 2 /* space <*/ + self.email.len() + 2 /* > space */ + self.time.size() + } + } + + fn validated_token(name: &BStr) -> Result<&BStr, Error> { + if name.find_byteset(b"<>\n").is_some() { + return Err(Error::IllegalCharacter); + } + Ok(name) + } +} + +/// +mod decode; +pub use decode::decode; |