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