##// END OF EJS Templates
rust: use NodePrefix::from_hex instead of hex::decode directly...
Simon Sapin -
r46647:88e741bf default
parent child Browse files
Show More
@@ -13,6 +13,8 b' use crate::revlog::manifest::{Manifest, '
13 use crate::revlog::path_encode::path_encode;
13 use crate::revlog::path_encode::path_encode;
14 use crate::revlog::revlog::Revlog;
14 use crate::revlog::revlog::Revlog;
15 use crate::revlog::revlog::RevlogError;
15 use crate::revlog::revlog::RevlogError;
16 use crate::revlog::Node;
17 use crate::revlog::NodePrefix;
16 use crate::revlog::Revision;
18 use crate::revlog::Revision;
17 use crate::utils::files::get_path_from_bytes;
19 use crate::utils::files::get_path_from_bytes;
18 use crate::utils::hg_path::{HgPath, HgPathBuf};
20 use crate::utils::hg_path::{HgPath, HgPathBuf};
@@ -108,15 +110,16 b" impl<'a> CatRev<'a> {"
108 let changelog_entry = match self.rev.parse::<Revision>() {
110 let changelog_entry = match self.rev.parse::<Revision>() {
109 Ok(rev) => self.changelog.get_rev(rev)?,
111 Ok(rev) => self.changelog.get_rev(rev)?,
110 _ => {
112 _ => {
111 let changelog_node = hex::decode(&self.rev)
113 let changelog_node = NodePrefix::from_hex(&self.rev)
112 .map_err(|_| CatRevErrorKind::InvalidRevision)?;
114 .map_err(|_| CatRevErrorKind::InvalidRevision)?;
113 self.changelog.get_node(&changelog_node)?
115 self.changelog.get_node(changelog_node.borrow())?
114 }
116 }
115 };
117 };
116 let manifest_node = hex::decode(&changelog_entry.manifest_node()?)
118 let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?)
117 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
119 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
118
120
119 self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?);
121 self.manifest_entry =
122 Some(self.manifest.get_node((&manifest_node).into())?);
120 if let Some(ref manifest_entry) = self.manifest_entry {
123 if let Some(ref manifest_entry) = self.manifest_entry {
121 let mut bytes = vec![];
124 let mut bytes = vec![];
122
125
@@ -132,9 +135,10 b" impl<'a> CatRev<'a> {"
132
135
133 let file_log =
136 let file_log =
134 Revlog::open(&index_path, Some(&data_path))?;
137 Revlog::open(&index_path, Some(&data_path))?;
135 let file_node = hex::decode(&node_bytes)
138 let file_node = Node::from_hex(node_bytes)
136 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
139 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
137 let file_rev = file_log.get_node_rev(&file_node)?;
140 let file_rev =
141 file_log.get_node_rev((&file_node).into())?;
138 let data = file_log.get_rev_data(file_rev)?;
142 let data = file_log.get_rev_data(file_rev)?;
139 if data.starts_with(&METADATA_DELIMITER) {
143 if data.starts_with(&METADATA_DELIMITER) {
140 let end_delimiter_position = data
144 let end_delimiter_position = data
@@ -7,6 +7,7 b''
7
7
8 use super::find_root;
8 use super::find_root;
9 use crate::revlog::revlog::{Revlog, RevlogError};
9 use crate::revlog::revlog::{Revlog, RevlogError};
10 use crate::revlog::NodePrefix;
10 use crate::revlog::Revision;
11 use crate::revlog::Revision;
11
12
12 /// Kind of data to debug
13 /// Kind of data to debug
@@ -107,9 +108,9 b" impl<'a> DebugData<'a> {"
107 let data = match self.rev.parse::<Revision>() {
108 let data = match self.rev.parse::<Revision>() {
108 Ok(rev) => revlog.get_rev_data(rev)?,
109 Ok(rev) => revlog.get_rev_data(rev)?,
109 _ => {
110 _ => {
110 let node = hex::decode(&self.rev)
111 let node = NodePrefix::from_hex(&self.rev)
111 .map_err(|_| DebugDataErrorKind::InvalidRevision)?;
112 .map_err(|_| DebugDataErrorKind::InvalidRevision)?;
112 let rev = revlog.get_node_rev(&node)?;
113 let rev = revlog.get_node_rev(node.borrow())?;
113 revlog.get_rev_data(rev)?
114 revlog.get_rev_data(rev)?
114 }
115 }
115 };
116 };
@@ -8,6 +8,7 b''
8 use crate::dirstate::parsers::parse_dirstate;
8 use crate::dirstate::parsers::parse_dirstate;
9 use crate::revlog::changelog::Changelog;
9 use crate::revlog::changelog::Changelog;
10 use crate::revlog::manifest::{Manifest, ManifestEntry};
10 use crate::revlog::manifest::{Manifest, ManifestEntry};
11 use crate::revlog::node::{Node, NodePrefix};
11 use crate::revlog::revlog::RevlogError;
12 use crate::revlog::revlog::RevlogError;
12 use crate::revlog::Revision;
13 use crate::revlog::Revision;
13 use crate::utils::hg_path::HgPath;
14 use crate::utils::hg_path::HgPath;
@@ -171,15 +172,16 b" impl<'a> ListRevTrackedFiles<'a> {"
171 let changelog_entry = match self.rev.parse::<Revision>() {
172 let changelog_entry = match self.rev.parse::<Revision>() {
172 Ok(rev) => self.changelog.get_rev(rev)?,
173 Ok(rev) => self.changelog.get_rev(rev)?,
173 _ => {
174 _ => {
174 let changelog_node = hex::decode(&self.rev)
175 let changelog_node = NodePrefix::from_hex(&self.rev)
175 .or(Err(ListRevTrackedFilesErrorKind::InvalidRevision))?;
176 .or(Err(ListRevTrackedFilesErrorKind::InvalidRevision))?;
176 self.changelog.get_node(&changelog_node)?
177 self.changelog.get_node(changelog_node.borrow())?
177 }
178 }
178 };
179 };
179 let manifest_node = hex::decode(&changelog_entry.manifest_node()?)
180 let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?)
180 .or(Err(ListRevTrackedFilesErrorKind::CorruptedRevlog))?;
181 .or(Err(ListRevTrackedFilesErrorKind::CorruptedRevlog))?;
181
182
182 self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?);
183 self.manifest_entry =
184 Some(self.manifest.get_node((&manifest_node).into())?);
183
185
184 if let Some(ref manifest_entry) = self.manifest_entry {
186 if let Some(ref manifest_entry) = self.manifest_entry {
185 Ok(manifest_entry.files())
187 Ok(manifest_entry.files())
@@ -1,4 +1,5 b''
1 use crate::revlog::revlog::{Revlog, RevlogError};
1 use crate::revlog::revlog::{Revlog, RevlogError};
2 use crate::revlog::NodePrefixRef;
2 use crate::revlog::Revision;
3 use crate::revlog::Revision;
3 use std::path::PathBuf;
4 use std::path::PathBuf;
4
5
@@ -19,7 +20,7 b' impl Changelog {'
19 /// Return the `ChangelogEntry` a given node id.
20 /// Return the `ChangelogEntry` a given node id.
20 pub fn get_node(
21 pub fn get_node(
21 &self,
22 &self,
22 node: &[u8],
23 node: NodePrefixRef,
23 ) -> Result<ChangelogEntry, RevlogError> {
24 ) -> Result<ChangelogEntry, RevlogError> {
24 let rev = self.revlog.get_node_rev(node)?;
25 let rev = self.revlog.get_node_rev(node)?;
25 self.get_rev(rev)
26 self.get_rev(rev)
@@ -1,7 +1,9 b''
1 use std::convert::TryInto;
1 use std::ops::Deref;
2 use std::ops::Deref;
2
3
3 use byteorder::{BigEndian, ByteOrder};
4 use byteorder::{BigEndian, ByteOrder};
4
5
6 use crate::revlog::node::Node;
5 use crate::revlog::revlog::RevlogError;
7 use crate::revlog::revlog::RevlogError;
6 use crate::revlog::{Revision, NULL_REVISION};
8 use crate::revlog::{Revision, NULL_REVISION};
7
9
@@ -188,8 +190,8 b" impl<'a> IndexEntry<'a> {"
188 ///
190 ///
189 /// Currently, SHA-1 is used and only the first 20 bytes of this field
191 /// Currently, SHA-1 is used and only the first 20 bytes of this field
190 /// are used.
192 /// are used.
191 pub fn hash(&self) -> &[u8] {
193 pub fn hash(&self) -> &Node {
192 &self.bytes[32..52]
194 (&self.bytes[32..52]).try_into().unwrap()
193 }
195 }
194 }
196 }
195
197
@@ -1,4 +1,5 b''
1 use crate::revlog::revlog::{Revlog, RevlogError};
1 use crate::revlog::revlog::{Revlog, RevlogError};
2 use crate::revlog::NodePrefixRef;
2 use crate::revlog::Revision;
3 use crate::revlog::Revision;
3 use crate::utils::hg_path::HgPath;
4 use crate::utils::hg_path::HgPath;
4 use std::path::PathBuf;
5 use std::path::PathBuf;
@@ -18,7 +19,10 b' impl Manifest {'
18 }
19 }
19
20
20 /// Return the `ManifestEntry` of a given node id.
21 /// Return the `ManifestEntry` of a given node id.
21 pub fn get_node(&self, node: &[u8]) -> Result<ManifestEntry, RevlogError> {
22 pub fn get_node(
23 &self,
24 node: NodePrefixRef,
25 ) -> Result<ManifestEntry, RevlogError> {
22 let rev = self.revlog.get_node_rev(node)?;
26 let rev = self.revlog.get_node_rev(node)?;
23 self.get_rev(rev)
27 self.get_rev(rev)
24 }
28 }
@@ -9,6 +9,7 b''
9 //! of a revision.
9 //! of a revision.
10
10
11 use hex::{self, FromHex, FromHexError};
11 use hex::{self, FromHex, FromHexError};
12 use std::convert::{TryFrom, TryInto};
12
13
13 /// The length in bytes of a `Node`
14 /// The length in bytes of a `Node`
14 ///
15 ///
@@ -65,6 +66,19 b' impl From<NodeData> for Node {'
65 }
66 }
66 }
67 }
67
68
69 /// Return an error if the slice has an unexpected length
70 impl<'a> TryFrom<&'a [u8]> for &'a Node {
71 type Error = std::array::TryFromSliceError;
72
73 #[inline]
74 fn try_from(bytes: &'a [u8]) -> Result<&'a Node, Self::Error> {
75 let data = bytes.try_into()?;
76 // Safety: `#[repr(transparent)]` makes it ok to "wrap" the target
77 // of a reference to the type of the single field.
78 Ok(unsafe { std::mem::transmute::<&NodeData, &Node>(data) })
79 }
80 }
81
68 #[derive(Debug, PartialEq)]
82 #[derive(Debug, PartialEq)]
69 pub enum NodeError {
83 pub enum NodeError {
70 ExactLengthRequired(usize, String),
84 ExactLengthRequired(usize, String),
@@ -103,8 +117,8 b' impl Node {'
103 ///
117 ///
104 /// To be used in FFI and I/O only, in order to facilitate future
118 /// To be used in FFI and I/O only, in order to facilitate future
105 /// changes of hash format.
119 /// changes of hash format.
106 pub fn from_hex(hex: &str) -> Result<Node, NodeError> {
120 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Node, NodeError> {
107 Ok(NodeData::from_hex(hex)
121 Ok(NodeData::from_hex(hex.as_ref())
108 .map_err(|e| NodeError::from((e, hex)))?
122 .map_err(|e| NodeError::from((e, hex)))?
109 .into())
123 .into())
110 }
124 }
@@ -126,17 +140,15 b' impl Node {'
126 }
140 }
127 }
141 }
128
142
129 impl<T: AsRef<str>> From<(FromHexError, T)> for NodeError {
143 impl<T: AsRef<[u8]>> From<(FromHexError, T)> for NodeError {
130 fn from(err_offender: (FromHexError, T)) -> Self {
144 fn from(err_offender: (FromHexError, T)) -> Self {
131 let (err, offender) = err_offender;
145 let (err, offender) = err_offender;
146 let offender = String::from_utf8_lossy(offender.as_ref()).into_owned();
132 match err {
147 match err {
133 FromHexError::InvalidStringLength => {
148 FromHexError::InvalidStringLength => {
134 NodeError::ExactLengthRequired(
149 NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, offender)
135 NODE_NYBBLES_LENGTH,
136 offender.as_ref().to_owned(),
137 )
138 }
150 }
139 _ => NodeError::HexError(err, offender.as_ref().to_owned()),
151 _ => NodeError::HexError(err, offender),
140 }
152 }
141 }
153 }
142 }
154 }
@@ -171,8 +183,8 b' impl NodePrefix {'
171
183
172 let is_odd = len % 2 == 1;
184 let is_odd = len % 2 == 1;
173 let even_part = if is_odd { &hex[..len - 1] } else { hex };
185 let even_part = if is_odd { &hex[..len - 1] } else { hex };
174 let mut buf: Vec<u8> = Vec::from_hex(&even_part)
186 let mut buf: Vec<u8> =
175 .map_err(|e| (e, String::from_utf8_lossy(hex)))?;
187 Vec::from_hex(&even_part).map_err(|e| (e, hex))?;
176
188
177 if is_odd {
189 if is_odd {
178 let latest_char = char::from(hex[len - 1]);
190 let latest_char = char::from(hex[len - 1]);
@@ -182,7 +194,7 b' impl NodePrefix {'
182 c: latest_char,
194 c: latest_char,
183 index: len - 1,
195 index: len - 1,
184 },
196 },
185 String::from_utf8_lossy(hex),
197 hex,
186 )
198 )
187 })? as u8;
199 })? as u8;
188 buf.push(latest_nybble << 4);
200 buf.push(latest_nybble << 4);
@@ -278,6 +290,12 b" impl<'a> From<&'a Node> for NodePrefixRe"
278 }
290 }
279 }
291 }
280
292
293 impl PartialEq<Node> for NodePrefixRef<'_> {
294 fn eq(&self, other: &Node) -> bool {
295 !self.is_odd && self.buf == other.data
296 }
297 }
298
281 #[cfg(test)]
299 #[cfg(test)]
282 mod tests {
300 mod tests {
283 use super::*;
301 use super::*;
@@ -292,7 +310,7 b' mod tests {'
292 }
310 }
293
311
294 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
312 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
295 ///
313 ///check_hash
296 /// The padding is made with zeros
314 /// The padding is made with zeros
297 pub fn hex_pad_right(hex: &str) -> String {
315 pub fn hex_pad_right(hex: &str) -> String {
298 let mut res = hex.to_string();
316 let mut res = hex.to_string();
@@ -13,7 +13,7 b' use micro_timer::timed;'
13 use zstd;
13 use zstd;
14
14
15 use super::index::Index;
15 use super::index::Index;
16 use super::node::{NODE_BYTES_LENGTH, NULL_NODE_ID};
16 use super::node::{NodePrefixRef, NODE_BYTES_LENGTH, NULL_NODE};
17 use super::patch;
17 use super::patch;
18 use crate::revlog::Revision;
18 use crate::revlog::Revision;
19
19
@@ -92,17 +92,20 b' impl Revlog {'
92
92
93 /// Return the full data associated to a node.
93 /// Return the full data associated to a node.
94 #[timed]
94 #[timed]
95 pub fn get_node_rev(&self, node: &[u8]) -> Result<Revision, RevlogError> {
95 pub fn get_node_rev(
96 &self,
97 node: NodePrefixRef,
98 ) -> Result<Revision, RevlogError> {
96 // This is brute force. But it is fast enough for now.
99 // This is brute force. But it is fast enough for now.
97 // Optimization will come later.
100 // Optimization will come later.
98 let mut found_by_prefix = None;
101 let mut found_by_prefix = None;
99 for rev in (0..self.len() as Revision).rev() {
102 for rev in (0..self.len() as Revision).rev() {
100 let index_entry =
103 let index_entry =
101 self.index.get_entry(rev).ok_or(RevlogError::Corrupted)?;
104 self.index.get_entry(rev).ok_or(RevlogError::Corrupted)?;
102 if index_entry.hash() == node {
105 if node == *index_entry.hash() {
103 return Ok(rev);
106 return Ok(rev);
104 }
107 }
105 if index_entry.hash().starts_with(node) {
108 if node.is_prefix_of(index_entry.hash()) {
106 if found_by_prefix.is_some() {
109 if found_by_prefix.is_some() {
107 return Err(RevlogError::AmbiguousPrefix);
110 return Err(RevlogError::AmbiguousPrefix);
108 }
111 }
@@ -143,7 +146,7 b' impl Revlog {'
143 if self.check_hash(
146 if self.check_hash(
144 index_entry.p1(),
147 index_entry.p1(),
145 index_entry.p2(),
148 index_entry.p2(),
146 index_entry.hash(),
149 index_entry.hash().as_bytes(),
147 &data,
150 &data,
148 ) {
151 ) {
149 Ok(data)
152 Ok(data)
@@ -163,15 +166,15 b' impl Revlog {'
163 let e1 = self.index.get_entry(p1);
166 let e1 = self.index.get_entry(p1);
164 let h1 = match e1 {
167 let h1 = match e1 {
165 Some(ref entry) => entry.hash(),
168 Some(ref entry) => entry.hash(),
166 None => &NULL_NODE_ID,
169 None => &NULL_NODE,
167 };
170 };
168 let e2 = self.index.get_entry(p2);
171 let e2 = self.index.get_entry(p2);
169 let h2 = match e2 {
172 let h2 = match e2 {
170 Some(ref entry) => entry.hash(),
173 Some(ref entry) => entry.hash(),
171 None => &NULL_NODE_ID,
174 None => &NULL_NODE,
172 };
175 };
173
176
174 hash(data, &h1, &h2).as_slice() == expected
177 hash(data, h1.as_bytes(), h2.as_bytes()).as_slice() == expected
175 }
178 }
176
179
177 /// Build the full data of a revision out its snapshot
180 /// Build the full data of a revision out its snapshot
@@ -115,8 +115,10 b' Specifying revisions by changeset ID'
115 $ rhg cat -r cf8b83 file-2
115 $ rhg cat -r cf8b83 file-2
116 2
116 2
117 $ rhg cat -r c file-2
117 $ rhg cat -r c file-2
118 abort: invalid revision identifier c
118 abort: ambiguous revision identifier c
119 [255]
119 [255]
120 $ rhg cat -r d file-2
121 2
120
122
121 Cat files
123 Cat files
122 $ cd $TESTTMP
124 $ cd $TESTTMP
General Comments 0
You need to be logged in to leave comments. Login now