Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-core/src/operations/cat.rs @ 46757:b1f2c2b336ec
rhg: `cat` command: print error messages for missing files
And exit with an error code if no file was matched.
This matches the behavior of Python-based hg.
Differential Revision: https://phab.mercurial-scm.org/D10142
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Wed, 03 Mar 2021 16:40:03 +0100 |
parents | 43d63979a75e |
children | d44740725b95 |
line wrap: on
line diff
--- a/rust/hg-core/src/operations/cat.rs Mon Mar 08 19:07:29 2021 +0100 +++ b/rust/hg-core/src/operations/cat.rs Wed Mar 03 16:40:03 2021 +0100 @@ -17,30 +17,49 @@ use crate::utils::files::get_path_from_bytes; use crate::utils::hg_path::{HgPath, HgPathBuf}; +pub struct CatOutput { + /// Whether any file in the manifest matched the paths given as CLI + /// arguments + pub found_any: bool, + /// The contents of matching files, in manifest order + pub concatenated: Vec<u8>, + /// Which of the CLI arguments did not match any manifest file + pub missing: Vec<HgPathBuf>, + /// The node ID that the given revset was resolved to + pub node: Node, +} + const METADATA_DELIMITER: [u8; 2] = [b'\x01', b'\n']; -/// List files under Mercurial control at a given revision. +/// Output the given revision of files /// /// * `root`: Repository root /// * `rev`: The revision to cat the files from. /// * `files`: The files to output. -pub fn cat( +pub fn cat<'a>( repo: &Repo, revset: &str, - files: &[HgPathBuf], -) -> Result<Vec<u8>, RevlogError> { + files: &'a [HgPathBuf], +) -> Result<CatOutput, RevlogError> { let rev = crate::revset::resolve_single(revset, repo)?; let changelog = Changelog::open(repo)?; let manifest = Manifest::open(repo)?; let changelog_entry = changelog.get_rev(rev)?; + let node = *changelog + .node_from_rev(rev) + .expect("should succeed when changelog.get_rev did"); let manifest_node = Node::from_hex_for_repo(&changelog_entry.manifest_node()?)?; let manifest_entry = manifest.get_node(manifest_node.into())?; let mut bytes = vec![]; + let mut matched = vec![false; files.len()]; + let mut found_any = false; for (manifest_file, node_bytes) in manifest_entry.files_with_nodes() { - for cat_file in files.iter() { + for (cat_file, is_matched) in files.iter().zip(&mut matched) { if cat_file.as_bytes() == manifest_file.as_bytes() { + *is_matched = true; + found_any = true; let index_path = store_path(manifest_file, b".i"); let data_path = store_path(manifest_file, b".d"); @@ -65,7 +84,18 @@ } } - Ok(bytes) + let missing: Vec<_> = files + .iter() + .zip(&matched) + .filter(|pair| !*pair.1) + .map(|pair| pair.0.clone()) + .collect(); + Ok(CatOutput { + found_any, + concatenated: bytes, + missing, + node, + }) } fn store_path(hg_path: &HgPath, suffix: &[u8]) -> PathBuf {