##// END OF EJS Templates
rhg: Also parse flags in the manifest parser...
Simon Sapin -
r49166:eb428010 default
parent child Browse files
Show More
@@ -12,6 +12,8 b' use crate::revlog::Node;'
12 use crate::utils::hg_path::HgPath;
12 use crate::utils::hg_path::HgPath;
13
13
14 use crate::errors::HgError;
14 use crate::errors::HgError;
15 use crate::manifest::Manifest;
16 use crate::manifest::ManifestEntry;
15 use itertools::put_back;
17 use itertools::put_back;
16 use itertools::PutBack;
18 use itertools::PutBack;
17 use std::cmp::Ordering;
19 use std::cmp::Ordering;
@@ -29,39 +31,33 b" pub struct CatOutput<'a> {"
29 }
31 }
30
32
31 // Find an item in an iterator over a sorted collection.
33 // Find an item in an iterator over a sorted collection.
32 fn find_item<'a, D, I: Iterator<Item = Result<(&'a HgPath, D), HgError>>>(
34 fn find_item<'a>(
33 i: &mut PutBack<I>,
35 i: &mut PutBack<impl Iterator<Item = Result<ManifestEntry<'a>, HgError>>>,
34 needle: &HgPath,
36 needle: &HgPath,
35 ) -> Result<Option<D>, HgError> {
37 ) -> Result<Option<Node>, HgError> {
36 loop {
38 loop {
37 match i.next() {
39 match i.next() {
38 None => return Ok(None),
40 None => return Ok(None),
39 Some(result) => {
41 Some(result) => {
40 let (path, value) = result?;
42 let entry = result?;
41 match needle.as_bytes().cmp(path.as_bytes()) {
43 match needle.as_bytes().cmp(entry.path.as_bytes()) {
42 Ordering::Less => {
44 Ordering::Less => {
43 i.put_back(Ok((path, value)));
45 i.put_back(Ok(entry));
44 return Ok(None);
46 return Ok(None);
45 }
47 }
46 Ordering::Greater => continue,
48 Ordering::Greater => continue,
47 Ordering::Equal => return Ok(Some(value)),
49 Ordering::Equal => return Ok(Some(entry.node_id()?)),
48 }
50 }
49 }
51 }
50 }
52 }
51 }
53 }
52 }
54 }
53
55
54 fn find_files_in_manifest<
56 fn find_files_in_manifest<'query>(
55 'manifest,
57 manifest: &Manifest,
56 'query,
58 query: impl Iterator<Item = &'query HgPath>,
57 Data,
59 ) -> Result<(Vec<(&'query HgPath, Node)>, Vec<&'query HgPath>), HgError> {
58 Manifest: Iterator<Item = Result<(&'manifest HgPath, Data), HgError>>,
60 let mut manifest = put_back(manifest.iter());
59 Query: Iterator<Item = &'query HgPath>,
60 >(
61 manifest: Manifest,
62 query: Query,
63 ) -> Result<(Vec<(&'query HgPath, Data)>, Vec<&'query HgPath>), HgError> {
64 let mut manifest = put_back(manifest);
65 let mut res = vec![];
61 let mut res = vec![];
66 let mut missing = vec![];
62 let mut missing = vec![];
67
63
@@ -96,14 +92,13 b" pub fn cat<'a>("
96 files.sort_unstable();
92 files.sort_unstable();
97
93
98 let (found, missing) = find_files_in_manifest(
94 let (found, missing) = find_files_in_manifest(
99 manifest.files_with_nodes(),
95 &manifest,
100 files.into_iter().map(|f| f.as_ref()),
96 files.into_iter().map(|f| f.as_ref()),
101 )?;
97 )?;
102
98
103 for (file_path, node_bytes) in found {
99 for (file_path, file_node) in found {
104 found_any = true;
100 found_any = true;
105 let file_log = repo.filelog(file_path)?;
101 let file_log = repo.filelog(file_path)?;
106 let file_node = Node::from_hex_for_repo(node_bytes)?;
107 results.push((
102 results.push((
108 file_path,
103 file_path,
109 file_log.data_for_node(file_node)?.into_data()?,
104 file_log.data_for_node(file_node)?.into_data()?,
@@ -77,6 +77,6 b' pub struct FilesForRev(Manifest);'
77
77
78 impl FilesForRev {
78 impl FilesForRev {
79 pub fn iter(&self) -> impl Iterator<Item = Result<&HgPath, HgError>> {
79 pub fn iter(&self) -> impl Iterator<Item = Result<&HgPath, HgError>> {
80 self.0.files()
80 self.0.iter().map(|entry| Ok(entry?.path))
81 }
81 }
82 }
82 }
@@ -4,6 +4,7 b' use crate::revlog::revlog::{Revlog, Revl'
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 {
@@ -55,50 +56,64 b' pub struct Manifest {'
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 }
@@ -309,13 +309,14 b' fn cat_file_is_modified('
309 manifest: &Manifest,
309 manifest: &Manifest,
310 hg_path: &HgPath,
310 hg_path: &HgPath,
311 ) -> Result<bool, HgError> {
311 ) -> Result<bool, HgError> {
312 let file_node = manifest
312 let entry = manifest
313 .find_file(hg_path)?
313 .find_file(hg_path)?
314 .expect("ambgious file not in p1");
314 .expect("ambgious file not in p1");
315 let filelog = repo.filelog(hg_path)?;
315 let filelog = repo.filelog(hg_path)?;
316 let filelog_entry = filelog.data_for_node(file_node).map_err(|_| {
316 let filelog_entry =
317 HgError::corrupted("filelog missing node from manifest")
317 filelog.data_for_node(entry.node_id()?).map_err(|_| {
318 })?;
318 HgError::corrupted("filelog missing node from manifest")
319 })?;
319 let contents_in_p1 = filelog_entry.data()?;
320 let contents_in_p1 = filelog_entry.data()?;
320
321
321 let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion");
322 let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion");
General Comments 0
You need to be logged in to leave comments. Login now