Mercurial > public > mercurial-scm > hg
diff rust/rhg/src/commands/cat.rs @ 45542:33ded2d3f4fc
rhg: add a limited `rhg cat -r` subcommand
It only supports revision specification (rev or full hash) and the list of files
to cat.
Differential Revision: https://phab.mercurial-scm.org/D9052
author | Antoine Cezar <antoine.cezar@octobus.net> |
---|---|
date | Tue, 15 Sep 2020 16:51:11 +0200 |
parents | |
children | db11f8f39caf |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/rhg/src/commands/cat.rs Tue Sep 15 16:51:11 2020 +0200 @@ -0,0 +1,99 @@ +use crate::commands::Command; +use crate::error::{CommandError, CommandErrorKind}; +use crate::ui::utf8_to_local; +use crate::ui::Ui; +use hg::operations::FindRoot; +use hg::operations::{CatRev, CatRevError, CatRevErrorKind}; +use hg::utils::hg_path::HgPathBuf; +use micro_timer::timed; +use std::convert::TryFrom; + +pub const HELP_TEXT: &str = " +Output the current or given revision of files +"; + +pub struct CatCommand<'a> { + rev: Option<&'a str>, + files: Vec<&'a str>, +} + +impl<'a> CatCommand<'a> { + pub fn new(rev: Option<&'a str>, files: Vec<&'a str>) -> Self { + Self { rev, files } + } + + fn display(&self, ui: &Ui, data: &[u8]) -> Result<(), CommandError> { + ui.write_stdout(data)?; + Ok(()) + } +} + +impl<'a> Command for CatCommand<'a> { + #[timed] + fn run(&self, ui: &Ui) -> Result<(), CommandError> { + let root = FindRoot::new().run()?; + let cwd = std::env::current_dir() + .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; + + let mut files = vec![]; + for file in self.files.iter() { + let normalized = cwd.join(&file); + let stripped = normalized + .strip_prefix(&root) + .map_err(|_| CommandErrorKind::Abort(None))?; + let hg_file = HgPathBuf::try_from(stripped.to_path_buf()) + .map_err(|_| CommandErrorKind::Abort(None))?; + files.push(hg_file); + } + + match self.rev { + Some(rev) => { + let mut operation = CatRev::new(&root, rev, &files) + .map_err(|e| map_rev_error(rev, e))?; + let data = + operation.run().map_err(|e| map_rev_error(rev, e))?; + self.display(ui, &data) + } + None => Err(CommandErrorKind::Unimplemented.into()), + } + } +} + +/// Convert `CatRevErrorKind` to `CommandError` +fn map_rev_error(rev: &str, err: CatRevError) -> CommandError { + CommandError { + kind: match err.kind { + CatRevErrorKind::IoError(err) => CommandErrorKind::Abort(Some( + utf8_to_local(&format!("abort: {}\n", err)).into(), + )), + CatRevErrorKind::InvalidRevision => CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: invalid revision identifier{}\n", + rev + )) + .into(), + )), + CatRevErrorKind::UnsuportedRevlogVersion(version) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unsupported revlog version {}\n", + version + )) + .into(), + )) + } + CatRevErrorKind::CorruptedRevlog => CommandErrorKind::Abort(Some( + "abort: corrupted revlog\n".into(), + )), + CatRevErrorKind::UnknowRevlogDataFormat(format) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unknow revlog dataformat {:?}\n", + format + )) + .into(), + )) + } + }, + } +}