Mercurial > hg
comparison rust/hg-core/src/revlog/filelog.rs @ 48237:027ebad952ac
rhg: internally, return a structured representation from hg cat
The purpose of this change is to make it possible to support limited templating in `hg cat`, so we could print separators between files etc.
The templating itself is not implemented yet, so this functionality is unused in `rhg cat`.
However, in our fork of hg we're implementing a slightly different command `hg jscat` which makes use of this.
So accepting this change will let us minimize the size of the patch we're maintaining on our side.
Differential Revision: https://phab.mercurial-scm.org/D11679
author | Arseniy Alekseyev <aalekseyev@janestreet.com> |
---|---|
date | Fri, 15 Oct 2021 14:05:20 +0100 |
parents | 87e3f878e65f |
children | e9faae0f445c |
comparison
equal
deleted
inserted
replaced
48236:f8dc78716ad2 | 48237:027ebad952ac |
---|---|
5 use crate::revlog::NodePrefix; | 5 use crate::revlog::NodePrefix; |
6 use crate::revlog::Revision; | 6 use crate::revlog::Revision; |
7 use crate::utils::files::get_path_from_bytes; | 7 use crate::utils::files::get_path_from_bytes; |
8 use crate::utils::hg_path::HgPath; | 8 use crate::utils::hg_path::HgPath; |
9 use crate::utils::SliceExt; | 9 use crate::utils::SliceExt; |
10 use std::borrow::Cow; | |
11 use std::path::PathBuf; | 10 use std::path::PathBuf; |
12 | 11 |
13 /// A specialized `Revlog` to work with file data logs. | 12 /// A specialized `Revlog` to work with file data logs. |
14 pub struct Filelog { | 13 pub struct Filelog { |
15 /// The generic `revlog` format. | 14 /// The generic `revlog` format. |
38 /// changeset. | 37 /// changeset. |
39 pub fn data_for_rev( | 38 pub fn data_for_rev( |
40 &self, | 39 &self, |
41 file_rev: Revision, | 40 file_rev: Revision, |
42 ) -> Result<FilelogEntry, RevlogError> { | 41 ) -> Result<FilelogEntry, RevlogError> { |
43 let data = self.revlog.get_rev_data(file_rev)?; | 42 let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?; |
44 Ok(FilelogEntry(data.into())) | 43 Ok(FilelogEntry(data.into())) |
45 } | 44 } |
46 } | 45 } |
47 | 46 |
48 fn store_path(hg_path: &HgPath, suffix: &[u8]) -> PathBuf { | 47 fn store_path(hg_path: &HgPath, suffix: &[u8]) -> PathBuf { |
49 let encoded_bytes = | 48 let encoded_bytes = |
50 path_encode(&[b"data/", hg_path.as_bytes(), suffix].concat()); | 49 path_encode(&[b"data/", hg_path.as_bytes(), suffix].concat()); |
51 get_path_from_bytes(&encoded_bytes).into() | 50 get_path_from_bytes(&encoded_bytes).into() |
52 } | 51 } |
53 | 52 |
54 pub struct FilelogEntry<'filelog>(Cow<'filelog, [u8]>); | 53 pub struct FilelogEntry(Vec<u8>); |
55 | 54 |
56 impl<'filelog> FilelogEntry<'filelog> { | 55 impl FilelogEntry { |
57 /// Split into metadata and data | 56 /// Split into metadata and data |
58 pub fn split(&self) -> Result<(Option<&[u8]>, &[u8]), HgError> { | 57 /// Returns None if there is no metadata, so the entire entry is data. |
58 fn split_metadata(&self) -> Result<Option<(&[u8], &[u8])>, HgError> { | |
59 const DELIMITER: &[u8; 2] = &[b'\x01', b'\n']; | 59 const DELIMITER: &[u8; 2] = &[b'\x01', b'\n']; |
60 | 60 |
61 if let Some(rest) = self.0.drop_prefix(DELIMITER) { | 61 if let Some(rest) = self.0.drop_prefix(DELIMITER) { |
62 if let Some((metadata, data)) = rest.split_2_by_slice(DELIMITER) { | 62 if let Some((metadata, data)) = rest.split_2_by_slice(DELIMITER) { |
63 Ok((Some(metadata), data)) | 63 Ok(Some((metadata, data))) |
64 } else { | 64 } else { |
65 Err(HgError::corrupted( | 65 Err(HgError::corrupted( |
66 "Missing metadata end delimiter in filelog entry", | 66 "Missing metadata end delimiter in filelog entry", |
67 )) | 67 )) |
68 } | 68 } |
69 } else { | |
70 Ok(None) | |
71 } | |
72 } | |
73 | |
74 /// Split into metadata and data | |
75 pub fn split(&self) -> Result<(Option<&[u8]>, &[u8]), HgError> { | |
76 if let Some((metadata, data)) = self.split_metadata()? { | |
77 Ok((Some(metadata), data)) | |
69 } else { | 78 } else { |
70 Ok((None, &self.0)) | 79 Ok((None, &self.0)) |
71 } | 80 } |
72 } | 81 } |
73 | 82 |
74 /// Returns the file contents at this revision, stripped of any metadata | 83 /// Returns the file contents at this revision, stripped of any metadata |
75 pub fn data(&self) -> Result<&[u8], HgError> { | 84 pub fn data(&self) -> Result<&[u8], HgError> { |
76 let (_metadata, data) = self.split()?; | 85 let (_metadata, data) = self.split()?; |
77 Ok(data) | 86 Ok(data) |
78 } | 87 } |
88 | |
89 /// Consume the entry, and convert it into data, discarding any metadata, | |
90 /// if present. | |
91 pub fn into_data(self) -> Result<Vec<u8>, HgError> { | |
92 if let Some((_metadata, data)) = self.split_metadata()? { | |
93 Ok(data.to_owned()) | |
94 } else { | |
95 Ok(self.0) | |
96 } | |
97 } | |
79 } | 98 } |