diff --git a/rust/rhg/src/commands/files.rs b/rust/rhg/src/commands/files.rs --- a/rust/rhg/src/commands/files.rs +++ b/rust/rhg/src/commands/files.rs @@ -7,8 +7,13 @@ ListDirstateTrackedFiles, ListDirstateTrackedFilesError, ListDirstateTrackedFilesErrorKind, }; +use hg::operations::{ + ListRevTrackedFiles, ListRevTrackedFilesError, + ListRevTrackedFilesErrorKind, +}; use hg::utils::files::{get_bytes_from_path, relativize_path}; -use hg::utils::hg_path::HgPathBuf; +use hg::utils::hg_path::{HgPath, HgPathBuf}; +use std::path::PathBuf; pub const HELP_TEXT: &str = " List tracked files. @@ -16,21 +21,21 @@ Returns 0 on success. "; -pub struct FilesCommand {} - -impl FilesCommand { - pub fn new() -> Self { - FilesCommand {} - } +pub struct FilesCommand<'a> { + rev: Option<&'a str>, } -impl Command for FilesCommand { - fn run(&self, ui: &Ui) -> Result<(), CommandError> { - let root = FindRoot::new().run()?; - let mut operation = ListDirstateTrackedFiles::new(&root) - .map_err(map_dirstate_error)?; - let files = operation.run().map_err(map_dirstate_error)?; +impl<'a> FilesCommand<'a> { + pub fn new(rev: Option<&'a str>) -> Self { + FilesCommand { rev } + } + fn display_files( + &self, + ui: &Ui, + root: &PathBuf, + files: impl IntoIterator, + ) -> Result<(), CommandError> { let cwd = std::env::current_dir() .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; let rooted_cwd = cwd @@ -49,7 +54,69 @@ } } -/// Convert operation errors to command errors +impl<'a> Command for FilesCommand<'a> { + fn run(&self, ui: &Ui) -> Result<(), CommandError> { + let root = FindRoot::new().run()?; + if let Some(rev) = self.rev { + let mut operation = ListRevTrackedFiles::new(&root, rev) + .map_err(|e| map_rev_error(rev, e))?; + let files = operation.run().map_err(|e| map_rev_error(rev, e))?; + self.display_files(ui, &root, files) + } else { + let mut operation = ListDirstateTrackedFiles::new(&root) + .map_err(map_dirstate_error)?; + let files = operation.run().map_err(map_dirstate_error)?; + self.display_files(ui, &root, files) + } + } +} + +/// Convert `ListRevTrackedFilesErrorKind` to `CommandError` +fn map_rev_error(rev: &str, err: ListRevTrackedFilesError) -> CommandError { + CommandError { + kind: match err.kind { + ListRevTrackedFilesErrorKind::IoError(err) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!("abort: {}\n", err)).into(), + )) + } + ListRevTrackedFilesErrorKind::InvalidRevision => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: invalid revision identifier{}\n", + rev + )) + .into(), + )) + } + ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unsupported revlog version {}\n", + version + )) + .into(), + )) + } + ListRevTrackedFilesErrorKind::CorruptedRevlog => { + CommandErrorKind::Abort(Some( + "abort: corrupted revlog\n".into(), + )) + } + ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) => { + CommandErrorKind::Abort(Some( + utf8_to_local(&format!( + "abort: unknow revlog dataformat {:?}\n", + format + )) + .into(), + )) + } + }, + } +} + +/// Convert `ListDirstateTrackedFilesError` to `CommandError` fn map_dirstate_error(err: ListDirstateTrackedFilesError) -> CommandError { CommandError { kind: match err.kind { diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs --- a/rust/rhg/src/main.rs +++ b/rust/rhg/src/main.rs @@ -26,7 +26,16 @@ SubCommand::with_name("root").about(commands::root::HELP_TEXT), ) .subcommand( - SubCommand::with_name("files").about(commands::files::HELP_TEXT), + SubCommand::with_name("files") + .arg( + Arg::with_name("rev") + .help("search the repository as it is in REV") + .short("-r") + .long("--revision") + .value_name("REV") + .takes_value(true), + ) + .about(commands::files::HELP_TEXT), ) .subcommand( SubCommand::with_name("debugdata") @@ -86,7 +95,9 @@ ) -> Result<(), CommandError> { match matches.subcommand() { ("root", _) => commands::root::RootCommand::new().run(&ui), - ("files", _) => commands::files::FilesCommand::new().run(&ui), + ("files", Some(matches)) => { + commands::files::FilesCommand::try_from(matches)?.run(&ui) + } ("debugdata", Some(matches)) => { commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) } @@ -94,6 +105,15 @@ } } +impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::files::FilesCommand<'a> { + type Error = CommandError; + + fn try_from(args: &'a ArgMatches) -> Result { + let rev = args.value_of("rev"); + Ok(commands::files::FilesCommand::new(rev)) + } +} + impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::debugdata::DebugDataCommand<'a> {