History

[git-ref] refactor

Sebastian Thiel committed 5 years ago

Commit 5bac5851 parent 30b0d546 files · +192 −199Browse files

Unified · Split

6 files
  1. git-ref/src/lib.rs +1 −21
  2. git-ref/src/safe_name.rs +19 −0
  3. git-ref/src/store/loose.rs +0 −178
  4. git-ref/src/store/loose/backend.rs +38 −0
  5. git-ref/src/store/loose/mod.rs +18 −0
  6. git-ref/src/store/loose/reference.rs +116 −0
git-ref/src/lib.rs+1−21
@@ -10,27 +10,7 @@ pub use store::*; · 9 unmodified lines
1010
1111 pub struct SafeName<'a>(&'a BStr);
1212
13−mod safe_name {
14− use crate::SafeName;
15− use bstr::{BStr, ByteSlice};
16− use std::convert::TryFrom;
17−
18− impl<'a> TryFrom<&'a BStr> for SafeName<'a> {
19− type Error = git_validate::reference::name::Error;
20−
21− fn try_from(v: &'a BStr) -> Result<Self, Self::Error> {
22− Ok(SafeName(git_validate::refname(v)?))
23− }
24− }
25−
26− impl<'a> TryFrom<&'a str> for SafeName<'a> {
27− type Error = git_validate::reference::name::Error;
28−
29− fn try_from(v: &'a str) -> Result<Self, Self::Error> {
30− Ok(SafeName(git_validate::refname(v.as_bytes().as_bstr())?))
31− }
32− }
33−}
13+mod safe_name;
3414
3515 /// Denotes the kind of function to produce a `Id`
3616 #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
git-ref/src/safe_name.rs+19−0
@@ -0,0 +1,19 @@
1+use crate::SafeName;
2+use bstr::{BStr, ByteSlice};
3+use std::convert::TryFrom;
4+
5+impl<'a> TryFrom<&'a BStr> for SafeName<'a> {
6+ type Error = git_validate::reference::name::Error;
7+
8+ fn try_from(v: &'a BStr) -> Result<Self, Self::Error> {
9+ Ok(SafeName(git_validate::refname(v)?))
10+ }
11+}
12+
13+impl<'a> TryFrom<&'a str> for SafeName<'a> {
14+ type Error = git_validate::reference::name::Error;
15+
16+ fn try_from(v: &'a str) -> Result<Self, Self::Error> {
17+ Ok(SafeName(git_validate::refname(v.as_bytes().as_bstr())?))
18+ }
19+}
git-ref/src/store/loose.rs+0−178
@@ -1,178 +0,0 @@
1−use std::path::PathBuf;
2−
3−#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
4−pub struct Reference<'a> {
5− parent: &'a Store,
6− /// The path relative to the stores base at which this reference is located
7− pub relative_path: PathBuf,
8− state: reference::State,
9−}
10−
11−#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
12−pub struct Store {
13− /// The location at which loose references can be found as per conventions of a typical git repository
14− pub base: PathBuf,
15−}
16−
17−mod backend {
18− mod find {
19− use crate::{loose, SafeName};
20− use quick_error::quick_error;
21− use std::convert::TryInto;
22−
23− quick_error! {
24− #[derive(Debug)]
25− pub enum Error {
26− Tbd
27− }
28− }
29−
30− impl loose::Store {
31− pub fn find_one<'a>(&self, _path: impl TryInto<SafeName<'a>>) -> Result<loose::Reference<'_>, Error> {
32− todo!("find one")
33− }
34− }
35− }
36−
37− mod init {
38− use crate::loose;
39− use std::path::PathBuf;
40−
41− impl loose::Store {
42− pub fn new(path: impl Into<PathBuf>) -> Self {
43− loose::Store { base: path.into() }
44− }
45− }
46−
47− impl<P> From<P> for loose::Store
48− where
49− P: Into<PathBuf>,
50− {
51− fn from(path: P) -> Self {
52− loose::Store::new(path)
53− }
54− }
55− }
56−}
57−
58−pub mod reference {
59− use crate::{loose::Reference, Kind, Target};
60− use bstr::BString;
61− use git_hash::ObjectId;
62−
63− #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
64− #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
65− pub(crate) enum State {
66− Id(ObjectId),
67− Path(BString),
68− }
69−
70− impl<'a> Reference<'a> {
71− pub fn kind(&self) -> Kind {
72− match self.state {
73− State::Path(_) => Kind::Symbolic,
74− State::Id(_) => Kind::Peeled,
75− }
76− }
77− pub fn target(&'a self) -> Target<'a> {
78− match self.state {
79− State::Path(ref path) => Target::Symbolic(path.as_ref()),
80− State::Id(ref oid) => Target::Peeled(oid.as_ref()),
81− }
82− }
83− }
84−
85− pub mod decode {
86− use crate::loose::{reference::State, Reference, Store};
87− use bstr::BString;
88− use git_hash::ObjectId;
89− use nom::{
90− branch::alt,
91− bytes::complete::take_while,
92− bytes::complete::{tag, take_while_m_n},
93− combinator::{map, opt},
94− sequence::terminated,
95− IResult,
96− };
97− use quick_error::quick_error;
98− use std::convert::TryInto;
99− use std::{convert::TryFrom, path::PathBuf};
100−
101− enum MaybeUnsafeState {
102− Id(ObjectId),
103− UnvalidatedPath(BString),
104− }
105−
106− quick_error! {
107− #[derive(Debug)]
108− pub enum Error {
109− Parse(content: BString) {
110− display("{:?} could not be parsed", content)
111− }
112− RefnameValidation{err: git_validate::reference::name::Error, path: BString} {
113− display("The path to a symbolic reference is invalid")
114− source(err)
115− }
116− }
117− }
118−
119− impl TryFrom<MaybeUnsafeState> for State {
120− type Error = Error;
121−
122− fn try_from(v: MaybeUnsafeState) -> Result<Self, Self::Error> {
123− Ok(match v {
124− MaybeUnsafeState::Id(id) => State::Id(id),
125− MaybeUnsafeState::UnvalidatedPath(path) => {
126− State::Path(match git_validate::refname(path.as_ref()) {
127− Err(err) => return Err(Error::RefnameValidation { err, path }),
128− Ok(_) => path,
129− })
130− }
131− })
132− }
133− }
134−
135− impl<'a> Reference<'a> {
136− pub fn try_from_path(
137− parent: &'a Store,
138− relative_path: impl Into<PathBuf>,
139− path_contents: &[u8],
140− ) -> Result<Self, Error> {
141− Ok(Reference {
142− parent,
143− relative_path: relative_path.into(),
144− state: parse(path_contents)
145− .map_err(|err| err.to_string())
146− .map_err(|_| Error::Parse(path_contents.into()))?
147− .1
148− .try_into()?,
149− })
150− }
151− }
152−
153− fn is_hex_digit_lc(b: u8) -> bool {
154− matches!(b, b'0'..=b'9' | b'a'..=b'f')
155− }
156−
157− fn hex_sha1(i: &[u8]) -> IResult<&[u8], &[u8]> {
158− take_while_m_n(40usize, 40, is_hex_digit_lc)(i)
159− }
160−
161− fn newline(i: &[u8]) -> IResult<&[u8], &[u8]> {
162− alt((tag(b"\r\n"), tag(b"\n")))(i)
163− }
164−
165− fn parse(bytes: &[u8]) -> IResult<&[u8], MaybeUnsafeState> {
166− let is_space = |b: u8| b == b' ';
167− if let (path, Some(_ref_prefix)) = opt(terminated(tag("ref: "), take_while(is_space)))(bytes)? {
168− map(terminated(take_while(|b| b != b'\r' && b != b'\n'), newline), |path| {
169− MaybeUnsafeState::UnvalidatedPath(path.into())
170− })(path)
171− } else {
172− map(terminated(hex_sha1, newline), |hex| {
173− MaybeUnsafeState::Id(ObjectId::from_hex(hex).expect("prior validation"))
174− })(bytes)
175− }
176− }
177− }
178−}
git-ref/src/store/loose/backend.rs+38−0
@@ -0,0 +1,38 @@
1+mod find {
2+ use crate::{loose, SafeName};
3+ use quick_error::quick_error;
4+ use std::convert::TryInto;
5+
6+ quick_error! {
7+ #[derive(Debug)]
8+ pub enum Error {
9+ Tbd
10+ }
11+ }
12+
13+ impl loose::Store {
14+ pub fn find_one<'a>(&self, _path: impl TryInto<SafeName<'a>>) -> Result<loose::Reference<'_>, Error> {
15+ todo!("find one")
16+ }
17+ }
18+}
19+
20+mod init {
21+ use crate::loose;
22+ use std::path::PathBuf;
23+
24+ impl loose::Store {
25+ pub fn new(path: impl Into<PathBuf>) -> Self {
26+ loose::Store { base: path.into() }
27+ }
28+ }
29+
30+ impl<P> From<P> for loose::Store
31+ where
32+ P: Into<PathBuf>,
33+ {
34+ fn from(path: P) -> Self {
35+ loose::Store::new(path)
36+ }
37+ }
38+}
git-ref/src/store/loose/mod.rs+18−0
@@ -0,0 +1,18 @@
1+use std::path::PathBuf;
2+
3+#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
4+pub struct Reference<'a> {
5+ parent: &'a Store,
6+ /// The path relative to the stores base at which this reference is located
7+ pub relative_path: PathBuf,
8+ state: reference::State,
9+}
10+
11+#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
12+pub struct Store {
13+ /// The location at which loose references can be found as per conventions of a typical git repository
14+ pub base: PathBuf,
15+}
16+
17+mod backend;
18+pub mod reference;
git-ref/src/store/loose/reference.rs+116−0
@@ -0,0 +1,116 @@
1+use crate::{loose::Reference, Kind, Target};
2+use bstr::BString;
3+use git_hash::ObjectId;
4+
5+#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
6+#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
7+pub(crate) enum State {
8+ Id(ObjectId),
9+ Path(BString),
10+}
11+
12+impl<'a> Reference<'a> {
13+ pub fn kind(&self) -> Kind {
14+ match self.state {
15+ State::Path(_) => Kind::Symbolic,
16+ State::Id(_) => Kind::Peeled,
17+ }
18+ }
19+ pub fn target(&'a self) -> Target<'a> {
20+ match self.state {
21+ State::Path(ref path) => Target::Symbolic(path.as_ref()),
22+ State::Id(ref oid) => Target::Peeled(oid.as_ref()),
23+ }
24+ }
25+}
26+
27+pub mod decode {
28+ use crate::loose::{reference::State, Reference, Store};
29+ use bstr::BString;
30+ use git_hash::ObjectId;
31+ use nom::{
32+ branch::alt,
33+ bytes::complete::take_while,
34+ bytes::complete::{tag, take_while_m_n},
35+ combinator::{map, opt},
36+ sequence::terminated,
37+ IResult,
38+ };
39+ use quick_error::quick_error;
40+ use std::convert::TryInto;
41+ use std::{convert::TryFrom, path::PathBuf};
42+
43+ enum MaybeUnsafeState {
44+ Id(ObjectId),
45+ UnvalidatedPath(BString),
46+ }
47+
48+ quick_error! {
49+ #[derive(Debug)]
50+ pub enum Error {
51+ Parse(content: BString) {
52+ display("{:?} could not be parsed", content)
53+ }
54+ RefnameValidation{err: git_validate::reference::name::Error, path: BString} {
55+ display("The path to a symbolic reference is invalid")
56+ source(err)
57+ }
58+ }
59+ }
60+
61+ impl TryFrom<MaybeUnsafeState> for State {
62+ type Error = Error;
63+
64+ fn try_from(v: MaybeUnsafeState) -> Result<Self, Self::Error> {
65+ Ok(match v {
66+ MaybeUnsafeState::Id(id) => State::Id(id),
67+ MaybeUnsafeState::UnvalidatedPath(path) => State::Path(match git_validate::refname(path.as_ref()) {
68+ Err(err) => return Err(Error::RefnameValidation { err, path }),
69+ Ok(_) => path,
70+ }),
71+ })
72+ }
73+ }
74+
75+ impl<'a> Reference<'a> {
76+ pub fn try_from_path(
77+ parent: &'a Store,
78+ relative_path: impl Into<PathBuf>,
79+ path_contents: &[u8],
80+ ) -> Result<Self, Error> {
81+ Ok(Reference {
82+ parent,
83+ relative_path: relative_path.into(),
84+ state: parse(path_contents)
85+ .map_err(|_| Error::Parse(path_contents.into()))?
86+ .1
87+ .try_into()?,
88+ })
89+ }
90+ }
91+
92+ fn is_hex_digit_lc(b: u8) -> bool {
93+ matches!(b, b'0'..=b'9' | b'a'..=b'f')
94+ }
95+
96+ fn hex_sha1(i: &[u8]) -> IResult<&[u8], &[u8]> {
97+ take_while_m_n(40usize, 40, is_hex_digit_lc)(i)
98+ }
99+
100+ fn newline(i: &[u8]) -> IResult<&[u8], &[u8]> {
101+ alt((tag(b"\r\n"), tag(b"\n")))(i)
102+ }
103+
104+ fn parse(bytes: &[u8]) -> IResult<&[u8], MaybeUnsafeState> {
105+ let is_space = |b: u8| b == b' ';
106+ if let (path, Some(_ref_prefix)) = opt(terminated(tag("ref: "), take_while(is_space)))(bytes)? {
107+ map(terminated(take_while(|b| b != b'\r' && b != b'\n'), newline), |path| {
108+ MaybeUnsafeState::UnvalidatedPath(path.into())
109+ })(path)
110+ } else {
111+ map(terminated(hex_sha1, newline), |hex| {
112+ MaybeUnsafeState::Id(ObjectId::from_hex(hex).expect("prior validation"))
113+ })(bytes)
114+ }
115+ }
116+}