Mercurial > hg
changeset 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 | 522ec3dc44b9 |
children | 68906595016c |
files | rust/rhg/src/commands.rs rust/rhg/src/commands/cat.rs rust/rhg/src/error.rs rust/rhg/src/main.rs |
diffstat | 4 files changed, 139 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/rhg/src/commands.rs Fri Sep 11 17:32:53 2020 +0200 +++ b/rust/rhg/src/commands.rs Tue Sep 15 16:51:11 2020 +0200 @@ -1,3 +1,4 @@ +pub mod cat; pub mod debugdata; pub mod files; pub mod root;
--- /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(), + )) + } + }, + } +}
--- a/rust/rhg/src/error.rs Fri Sep 11 17:32:53 2020 +0200 +++ b/rust/rhg/src/error.rs Tue Sep 15 16:51:11 2020 +0200 @@ -18,6 +18,8 @@ StderrError, /// The command aborted Abort(Option<Vec<u8>>), + /// A mercurial capability as not been implemented. + Unimplemented, } impl CommandErrorKind { @@ -28,6 +30,7 @@ CommandErrorKind::StdoutError => exitcode::ABORT, CommandErrorKind::StderrError => exitcode::ABORT, CommandErrorKind::Abort(_) => exitcode::ABORT, + CommandErrorKind::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND, } }
--- a/rust/rhg/src/main.rs Fri Sep 11 17:32:53 2020 +0200 +++ b/rust/rhg/src/main.rs Tue Sep 15 16:51:11 2020 +0200 @@ -38,6 +38,26 @@ .about(commands::files::HELP_TEXT), ) .subcommand( + SubCommand::with_name("cat") + .arg( + Arg::with_name("rev") + .help("search the repository as it is in REV") + .short("-r") + .long("--revision") + .value_name("REV") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("files") + .required(true) + .multiple(true) + .empty_values(false) + .value_name("FILE") + .help("Activity to start: activity@category"), + ) + .about(commands::cat::HELP_TEXT), + ) + .subcommand( SubCommand::with_name("debugdata") .about(commands::debugdata::HELP_TEXT) .arg( @@ -98,6 +118,9 @@ ("files", Some(matches)) => { commands::files::FilesCommand::try_from(matches)?.run(&ui) } + ("cat", Some(matches)) => { + commands::cat::CatCommand::try_from(matches)?.run(&ui) + } ("debugdata", Some(matches)) => { commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) } @@ -114,6 +137,19 @@ } } +impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::cat::CatCommand<'a> { + type Error = CommandError; + + fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { + let rev = args.value_of("rev"); + let files = match args.values_of("files") { + Some(files) => files.collect(), + None => vec![], + }; + Ok(commands::cat::CatCommand::new(rev, files)) + } +} + impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::debugdata::DebugDataCommand<'a> {