Show More
@@ -11,6 +11,7 b' use crate::revlog::Node;' | |||
|
11 | 11 | |
|
12 | 12 | use crate::utils::hg_path::HgPath; |
|
13 | 13 | |
|
14 | use crate::errors::HgError; | |
|
14 | 15 | use itertools::put_back; |
|
15 | 16 | use itertools::PutBack; |
|
16 | 17 | use std::cmp::Ordering; |
@@ -28,21 +29,24 b" pub struct CatOutput<'a> {" | |||
|
28 | 29 | } |
|
29 | 30 | |
|
30 | 31 | // Find an item in an iterator over a sorted collection. |
|
31 |
fn find_item<'a |
|
|
32 | fn find_item<'a, D, I: Iterator<Item = Result<(&'a HgPath, D), HgError>>>( | |
|
32 | 33 | i: &mut PutBack<I>, |
|
33 |
needle: & |
|
|
34 | ) -> Option<D> { | |
|
34 | needle: &HgPath, | |
|
35 | ) -> Result<Option<D>, HgError> { | |
|
35 | 36 | loop { |
|
36 | 37 | match i.next() { |
|
37 | None => return None, | |
|
38 | Some(val) => match needle.as_bytes().cmp(val.0.as_bytes()) { | |
|
39 | Ordering::Less => { | |
|
40 | i.put_back(val); | |
|
41 |
re |
|
|
38 | None => return Ok(None), | |
|
39 | Some(result) => { | |
|
40 | let (path, value) = result?; | |
|
41 | match needle.as_bytes().cmp(path.as_bytes()) { | |
|
42 | Ordering::Less => { | |
|
43 | i.put_back(Ok((path, value))); | |
|
44 | return Ok(None); | |
|
45 | } | |
|
46 | Ordering::Greater => continue, | |
|
47 | Ordering::Equal => return Ok(Some(value)), | |
|
42 | 48 | } |
|
43 | Ordering::Greater => continue, | |
|
44 | Ordering::Equal => return Some(val.1), | |
|
45 | }, | |
|
49 | } | |
|
46 | 50 | } |
|
47 | 51 | } |
|
48 | 52 | } |
@@ -51,23 +55,23 b' fn find_files_in_manifest<' | |||
|
51 | 55 | 'manifest, |
|
52 | 56 | 'query, |
|
53 | 57 | Data, |
|
54 | Manifest: Iterator<Item = (&'manifest HgPath, Data)>, | |
|
58 | Manifest: Iterator<Item = Result<(&'manifest HgPath, Data), HgError>>, | |
|
55 | 59 | Query: Iterator<Item = &'query HgPath>, |
|
56 | 60 | >( |
|
57 | 61 | manifest: Manifest, |
|
58 | 62 | query: Query, |
|
59 | ) -> (Vec<(&'query HgPath, Data)>, Vec<&'query HgPath>) { | |
|
63 | ) -> Result<(Vec<(&'query HgPath, Data)>, Vec<&'query HgPath>), HgError> { | |
|
60 | 64 | let mut manifest = put_back(manifest); |
|
61 | 65 | let mut res = vec![]; |
|
62 | 66 | let mut missing = vec![]; |
|
63 | 67 | |
|
64 | 68 | for file in query { |
|
65 | match find_item(&mut manifest, file) { | |
|
69 | match find_item(&mut manifest, file)? { | |
|
66 | 70 | None => missing.push(file), |
|
67 | 71 | Some(item) => res.push((file, item)), |
|
68 | 72 | } |
|
69 | 73 | } |
|
70 | return (res, missing); | |
|
74 | return Ok((res, missing)); | |
|
71 | 75 | } |
|
72 | 76 | |
|
73 | 77 | /// Output the given revision of files |
@@ -94,7 +98,7 b" pub fn cat<'a>(" | |||
|
94 | 98 | let (found, missing) = find_files_in_manifest( |
|
95 | 99 | manifest.files_with_nodes(), |
|
96 | 100 | files.into_iter().map(|f| f.as_ref()), |
|
97 | ); | |
|
101 | )?; | |
|
98 | 102 | |
|
99 | 103 | for (file_path, node_bytes) in found { |
|
100 | 104 | found_any = true; |
@@ -76,7 +76,7 b' pub fn list_rev_tracked_files(' | |||
|
76 | 76 | pub struct FilesForRev(Manifest); |
|
77 | 77 | |
|
78 | 78 | impl FilesForRev { |
|
79 | pub fn iter(&self) -> impl Iterator<Item = &HgPath> { | |
|
79 | pub fn iter(&self) -> impl Iterator<Item = Result<&HgPath, HgError>> { | |
|
80 | 80 | self.0.files() |
|
81 | 81 | } |
|
82 | 82 | } |
@@ -63,26 +63,28 b' impl Manifest {' | |||
|
63 | 63 | } |
|
64 | 64 | |
|
65 | 65 | /// Return an iterator over the files of the entry. |
|
66 | pub fn files(&self) -> impl Iterator<Item = &HgPath> { | |
|
66 | pub fn files(&self) -> impl Iterator<Item = Result<&HgPath, HgError>> { | |
|
67 | 67 | self.lines().filter(|line| !line.is_empty()).map(|line| { |
|
68 |
let pos = |
|
|
69 | .iter() | |
|
70 | .position(|x| x == &b'\0') | |
|
71 | .expect("manifest line should contain \\0"); | |
|
72 | HgPath::new(&line[..pos]) | |
|
68 | let pos = | |
|
69 | line.iter().position(|x| x == &b'\0').ok_or_else(|| { | |
|
70 | HgError::corrupted("manifest line should contain \\0") | |
|
71 | })?; | |
|
72 | Ok(HgPath::new(&line[..pos])) | |
|
73 | 73 | }) |
|
74 | 74 | } |
|
75 | 75 | |
|
76 | 76 | /// Return an iterator over the files of the entry. |
|
77 | pub fn files_with_nodes(&self) -> impl Iterator<Item = (&HgPath, &[u8])> { | |
|
77 | pub fn files_with_nodes( | |
|
78 | &self, | |
|
79 | ) -> impl Iterator<Item = Result<(&HgPath, &[u8]), HgError>> { | |
|
78 | 80 | self.lines().filter(|line| !line.is_empty()).map(|line| { |
|
79 |
let pos = |
|
|
80 | .iter() | |
|
81 | .position(|x| x == &b'\0') | |
|
82 | .expect("manifest line should contain \\0"); | |
|
81 | let pos = | |
|
82 | line.iter().position(|x| x == &b'\0').ok_or_else(|| { | |
|
83 | HgError::corrupted("manifest line should contain \\0") | |
|
84 | })?; | |
|
83 | 85 | let hash_start = pos + 1; |
|
84 | 86 | let hash_end = hash_start + 40; |
|
85 | (HgPath::new(&line[..pos]), &line[hash_start..hash_end]) | |
|
87 | Ok((HgPath::new(&line[..pos]), &line[hash_start..hash_end])) | |
|
86 | 88 | }) |
|
87 | 89 | } |
|
88 | 90 | |
@@ -91,7 +93,8 b' impl Manifest {' | |||
|
91 | 93 | // TODO: use binary search instead of linear scan. This may involve |
|
92 | 94 | // building (and caching) an index of the byte indicex of each manifest |
|
93 | 95 | // line. |
|
94 |
for |
|
|
96 | for entry in self.files_with_nodes() { | |
|
97 | let (manifest_path, node) = entry?; | |
|
95 | 98 | if manifest_path == path { |
|
96 | 99 | return Ok(Some(Node::from_hex_for_repo(node)?)); |
|
97 | 100 | } |
@@ -3,6 +3,7 b' use crate::ui::Ui;' | |||
|
3 | 3 | use crate::ui::UiError; |
|
4 | 4 | use crate::utils::path_utils::relativize_paths; |
|
5 | 5 | use clap::Arg; |
|
6 | use hg::errors::HgError; | |
|
6 | 7 | use hg::operations::list_rev_tracked_files; |
|
7 | 8 | use hg::operations::Dirstate; |
|
8 | 9 | use hg::repo::Repo; |
@@ -45,14 +46,14 b' pub fn run(invocation: &crate::CliInvoca' | |||
|
45 | 46 | } else { |
|
46 | 47 | let distate = Dirstate::new(repo)?; |
|
47 | 48 | let files = distate.tracked_files()?; |
|
48 | display_files(invocation.ui, repo, files) | |
|
49 | display_files(invocation.ui, repo, files.into_iter().map(Ok)) | |
|
49 | 50 | } |
|
50 | 51 | } |
|
51 | 52 | |
|
52 | 53 | fn display_files<'a>( |
|
53 | 54 | ui: &Ui, |
|
54 | 55 | repo: &Repo, |
|
55 | files: impl IntoIterator<Item = &'a HgPath>, | |
|
56 | files: impl IntoIterator<Item = Result<&'a HgPath, HgError>>, | |
|
56 | 57 | ) -> Result<(), CommandError> { |
|
57 | 58 | let mut stdout = ui.stdout_buffer(); |
|
58 | 59 | let mut any = false; |
@@ -279,7 +279,7 b' fn display_status_paths(' | |||
|
279 | 279 | if relative && !ui.plain() { |
|
280 | 280 | relativize_paths( |
|
281 | 281 | repo, |
|
282 | paths, | |
|
282 | paths.iter().map(Ok), | |
|
283 | 283 | |path: Cow<[u8]>| -> Result<(), UiError> { |
|
284 | 284 | ui.write_stdout( |
|
285 | 285 | &[status_prefix, b" ", path.as_ref(), b"\n"].concat(), |
@@ -5,6 +5,7 b'' | |||
|
5 | 5 | |
|
6 | 6 | use crate::error::CommandError; |
|
7 | 7 | use crate::ui::UiError; |
|
8 | use hg::errors::HgError; | |
|
8 | 9 | use hg::repo::Repo; |
|
9 | 10 | use hg::utils::current_dir; |
|
10 | 11 | use hg::utils::files::{get_bytes_from_path, relativize_path}; |
@@ -14,7 +15,7 b' use std::borrow::Cow;' | |||
|
14 | 15 | |
|
15 | 16 | pub fn relativize_paths( |
|
16 | 17 | repo: &Repo, |
|
17 | paths: impl IntoIterator<Item = impl AsRef<HgPath>>, | |
|
18 | paths: impl IntoIterator<Item = Result<impl AsRef<HgPath>, HgError>>, | |
|
18 | 19 | mut callback: impl FnMut(Cow<[u8]>) -> Result<(), UiError>, |
|
19 | 20 | ) -> Result<(), CommandError> { |
|
20 | 21 | let cwd = current_dir()?; |
@@ -38,10 +39,10 b' pub fn relativize_paths(' | |||
|
38 | 39 | |
|
39 | 40 | for file in paths { |
|
40 | 41 | if outside_repo { |
|
41 | let file = repo_root_hgpath.join(file.as_ref()); | |
|
42 | let file = repo_root_hgpath.join(file?.as_ref()); | |
|
42 | 43 | callback(relativize_path(&file, &cwd_hgpath))?; |
|
43 | 44 | } else { |
|
44 | callback(relativize_path(file.as_ref(), &cwd_hgpath))?; | |
|
45 | callback(relativize_path(file?.as_ref(), &cwd_hgpath))?; | |
|
45 | 46 | } |
|
46 | 47 | } |
|
47 | 48 | Ok(()) |
General Comments 0
You need to be logged in to leave comments.
Login now