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 }