##// 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 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, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>(
32 fn find_item<'a, D, I: Iterator<Item = Result<(&'a HgPath, D), HgError>>>(
32 33 i: &mut PutBack<I>,
33 needle: &'b HgPath,
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()) {
38 None => return Ok(None),
39 Some(result) => {
40 let (path, value) = result?;
41 match needle.as_bytes().cmp(path.as_bytes()) {
39 42 Ordering::Less => {
40 i.put_back(val);
41 return None;
43 i.put_back(Ok((path, value)));
44 return Ok(None);
42 45 }
43 46 Ordering::Greater => continue,
44 Ordering::Equal => return Some(val.1),
45 },
47 Ordering::Equal => return Ok(Some(value)),
48 }
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 = line
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 = line
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 (manifest_path, node) in self.files_with_nodes() {
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