##// END OF EJS Templates
rhg: Propogate manifest parse errors instead of panicking...
Simon Sapin -
r49165:10c32e1b default
parent child Browse files
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, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>(
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: &'b HgPath,
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 return None;
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 = line
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 = line
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 (manifest_path, node) in self.files_with_nodes() {
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