diff --git a/rust/hg-core/src/operations/cat.rs b/rust/hg-core/src/operations/cat.rs --- a/rust/hg-core/src/operations/cat.rs +++ b/rust/hg-core/src/operations/cat.rs @@ -9,12 +9,9 @@ use crate::revlog::revlog::RevlogError; use crate::revlog::Node; -use crate::utils::hg_path::HgPath; use crate::utils::hg_path::HgPathBuf; -use itertools::put_back; -use itertools::PutBack; -use std::cmp::Ordering; +use std::collections::HashSet; pub struct CatOutput { /// Whether any file in the manifest matched the paths given as CLI @@ -28,49 +25,6 @@ pub node: Node, } -// Find an item in an iterator over a sorted collection. -fn find_item<'a, 'b, 'c, D, I: Iterator>( - i: &mut PutBack, - needle: &'b HgPath, -) -> Option { - loop { - match i.next() { - None => return None, - Some(val) => match needle.as_bytes().cmp(val.0.as_bytes()) { - Ordering::Less => { - i.put_back(val); - return None; - } - Ordering::Greater => continue, - Ordering::Equal => return Some(val), - }, - } - } -} - -fn find_files_in_manifest< - 'a, - 'b, - D, - I: Iterator, - J: Iterator, ->( - manifest: I, - files: J, -) -> (Vec<(&'a HgPath, D)>, Vec<&'b HgPath>) { - let mut manifest = put_back(manifest); - let mut res = vec![]; - let mut missing = vec![]; - - for file in files { - match find_item(&mut manifest, file) { - None => missing.push(file), - Some(item) => res.push(item), - } - } - return (res, missing); -} - /// Output the given revision of files /// /// * `root`: Repository root @@ -79,7 +33,7 @@ pub fn cat<'a>( repo: &Repo, revset: &str, - mut files: Vec, + files: &[HgPathBuf], ) -> Result { let rev = crate::revset::resolve_single(revset, repo)?; let manifest = repo.manifest_for_rev(rev)?; @@ -87,30 +41,24 @@ .changelog()? .node_from_rev(rev) .expect("should succeed when repo.manifest did"); + + let mut missing: HashSet<_> = files.iter().map(|x| x.as_ref()).collect(); let mut bytes: Vec = vec![]; - let mut found_any = false; - - files.sort_unstable(); - - let (found, missing) = find_files_in_manifest( - manifest.files_with_nodes(), - files.iter().map(|f| f.as_ref()), - ); - - for (manifest_file, node_bytes) in found { - found_any = true; - let file_log = repo.filelog(manifest_file)?; - let file_node = Node::from_hex_for_repo(node_bytes)?; - bytes.extend(file_log.data_for_node(file_node)?.data()?); + if let Some(last_path) = files.iter().max() { + for (path, node_bytes) in manifest.files_with_nodes() { + if missing.remove(&*path) { + let file_log = repo.filelog(path)?; + let file_node = Node::from_hex_for_repo(node_bytes)?; + bytes.extend(file_log.data_for_node(file_node)?.data()?); + } + if path >= last_path { + break; + } + } } - - // make the order of the [missing] files - // match the order they were specified on the command line - let missing: Vec<_> = files - .iter() - .filter(|file| missing.contains(&file.as_ref())) - .map(|file| file.clone()) - .collect(); + let found_any = missing.len() != files.len(); + let missing: Vec<_> = + missing.into_iter().map(|path| path.to_owned()).collect(); Ok(CatOutput { found_any, concatenated: bytes, diff --git a/rust/rhg/src/commands/cat.rs b/rust/rhg/src/commands/cat.rs --- a/rust/rhg/src/commands/cat.rs +++ b/rust/rhg/src/commands/cat.rs @@ -73,7 +73,7 @@ None => format!("{:x}", repo.dirstate_parents()?.p1), }; - let output = cat(&repo, &rev, files).map_err(|e| (e, rev.as_str()))?; + let output = cat(&repo, &rev, &files).map_err(|e| (e, rev.as_str()))?; invocation.ui.write_stdout(&output.concatenated)?; if !output.missing.is_empty() { let short = format!("{:x}", output.node.short()).into_bytes();