Mercurial > hg
comparison rust/hg-core/src/revlog/manifest.rs @ 48343:eb428010aad2
rhg: Also parse flags in the manifest parser
Differential Revision: https://phab.mercurial-scm.org/D11772
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Tue, 23 Nov 2021 19:39:51 +0100 |
parents | 10c32e1b892a |
children | e293ff808a05 |
comparison
equal
deleted
inserted
replaced
48342:10c32e1b892a | 48343:eb428010aad2 |
---|---|
2 use crate::repo::Repo; | 2 use crate::repo::Repo; |
3 use crate::revlog::revlog::{Revlog, RevlogError}; | 3 use crate::revlog::revlog::{Revlog, RevlogError}; |
4 use crate::revlog::Revision; | 4 use crate::revlog::Revision; |
5 use crate::revlog::{Node, NodePrefix}; | 5 use crate::revlog::{Node, NodePrefix}; |
6 use crate::utils::hg_path::HgPath; | 6 use crate::utils::hg_path::HgPath; |
7 use crate::utils::SliceExt; | |
7 | 8 |
8 /// A specialized `Revlog` to work with `manifest` data format. | 9 /// A specialized `Revlog` to work with `manifest` data format. |
9 pub struct Manifestlog { | 10 pub struct Manifestlog { |
10 /// The generic `revlog` format. | 11 /// The generic `revlog` format. |
11 revlog: Revlog, | 12 revlog: Revlog, |
53 pub struct Manifest { | 54 pub struct Manifest { |
54 bytes: Vec<u8>, | 55 bytes: Vec<u8>, |
55 } | 56 } |
56 | 57 |
57 impl Manifest { | 58 impl Manifest { |
58 /// Return an iterator over the lines of the entry. | 59 pub fn iter( |
59 pub fn lines(&self) -> impl Iterator<Item = &[u8]> { | 60 &self, |
61 ) -> impl Iterator<Item = Result<ManifestEntry, HgError>> { | |
60 self.bytes | 62 self.bytes |
61 .split(|b| b == &b'\n') | 63 .split(|b| b == &b'\n') |
62 .filter(|line| !line.is_empty()) | 64 .filter(|line| !line.is_empty()) |
63 } | 65 .map(|line| { |
64 | 66 let (path, rest) = line.split_2(b'\0').ok_or_else(|| { |
65 /// Return an iterator over the files of the entry. | |
66 pub fn files(&self) -> impl Iterator<Item = Result<&HgPath, HgError>> { | |
67 self.lines().filter(|line| !line.is_empty()).map(|line| { | |
68 let pos = | |
69 line.iter().position(|x| x == &b'\0').ok_or_else(|| { | |
70 HgError::corrupted("manifest line should contain \\0") | 67 HgError::corrupted("manifest line should contain \\0") |
71 })?; | 68 })?; |
72 Ok(HgPath::new(&line[..pos])) | 69 let path = HgPath::new(path); |
73 }) | 70 let (hex_node_id, flags) = match rest.split_last() { |
74 } | 71 Some((&b'x', rest)) => (rest, Some(b'x')), |
75 | 72 Some((&b'l', rest)) => (rest, Some(b'l')), |
76 /// Return an iterator over the files of the entry. | 73 Some((&b't', rest)) => (rest, Some(b't')), |
77 pub fn files_with_nodes( | 74 _ => (rest, None), |
78 &self, | 75 }; |
79 ) -> impl Iterator<Item = Result<(&HgPath, &[u8]), HgError>> { | 76 Ok(ManifestEntry { |
80 self.lines().filter(|line| !line.is_empty()).map(|line| { | 77 path, |
81 let pos = | 78 hex_node_id, |
82 line.iter().position(|x| x == &b'\0').ok_or_else(|| { | 79 flags, |
83 HgError::corrupted("manifest line should contain \\0") | 80 }) |
84 })?; | 81 }) |
85 let hash_start = pos + 1; | |
86 let hash_end = hash_start + 40; | |
87 Ok((HgPath::new(&line[..pos]), &line[hash_start..hash_end])) | |
88 }) | |
89 } | 82 } |
90 | 83 |
91 /// If the given path is in this manifest, return its filelog node ID | 84 /// If the given path is in this manifest, return its filelog node ID |
92 pub fn find_file(&self, path: &HgPath) -> Result<Option<Node>, HgError> { | 85 pub fn find_file( |
86 &self, | |
87 path: &HgPath, | |
88 ) -> Result<Option<ManifestEntry>, HgError> { | |
93 // TODO: use binary search instead of linear scan. This may involve | 89 // TODO: use binary search instead of linear scan. This may involve |
94 // building (and caching) an index of the byte indicex of each manifest | 90 // building (and caching) an index of the byte indicex of each manifest |
95 // line. | 91 // line. |
96 for entry in self.files_with_nodes() { | 92 |
97 let (manifest_path, node) = entry?; | 93 // TODO: use try_find when available (if still using linear scan) |
98 if manifest_path == path { | 94 // https://github.com/rust-lang/rust/issues/63178 |
99 return Ok(Some(Node::from_hex_for_repo(node)?)); | 95 for entry in self.iter() { |
96 let entry = entry?; | |
97 if entry.path == path { | |
98 return Ok(Some(entry)); | |
100 } | 99 } |
101 } | 100 } |
102 Ok(None) | 101 Ok(None) |
103 } | 102 } |
104 } | 103 } |
104 | |
105 /// `Manifestlog` entry which knows how to interpret the `manifest` data bytes. | |
106 #[derive(Debug)] | |
107 pub struct ManifestEntry<'manifest> { | |
108 pub path: &'manifest HgPath, | |
109 pub hex_node_id: &'manifest [u8], | |
110 | |
111 /// `Some` values are b'x', b'l', or 't' | |
112 pub flags: Option<u8>, | |
113 } | |
114 | |
115 impl ManifestEntry<'_> { | |
116 pub fn node_id(&self) -> Result<Node, HgError> { | |
117 Node::from_hex_for_repo(self.hex_node_id) | |
118 } | |
119 } |