changeset 45537:2f8227a12592

rhg: add `--revision` argument to `rhg files` Add the option to list the tracked files of a revision given its number or full node id. Benched on a clone of moz-central where tip is 1671467:81deaa1a68ebb28db0490954034ab38ab269409d files -r 81deaa1a68ebb28db0490954034ab38ab269409d > out.txt hg 0m1.633s rhg 0m0.157s files -r 81deaa1a68ebb28db0490954034ab38ab269409d > /dev/null hg 0m0.415s rhg 0m0.143s Differential Revision: https://phab.mercurial-scm.org/D9015
author Antoine Cezar <antoine.cezar@octobus.net>
date Wed, 09 Sep 2020 14:53:15 +0200
parents 639f33f22faf
children 2d5dfc8fed55
files rust/rhg/src/commands/files.rs rust/rhg/src/main.rs
diffstat 2 files changed, 103 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/rust/rhg/src/commands/files.rs	Fri Sep 18 16:52:16 2020 +0200
+++ b/rust/rhg/src/commands/files.rs	Wed Sep 09 14:53:15 2020 +0200
@@ -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<Item = &'a HgPath>,
+    ) -> 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 {
--- a/rust/rhg/src/main.rs	Fri Sep 18 16:52:16 2020 +0200
+++ b/rust/rhg/src/main.rs	Wed Sep 09 14:53:15 2020 +0200
@@ -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<Self, Self::Error> {
+        let rev = args.value_of("rev");
+        Ok(commands::files::FilesCommand::new(rev))
+    }
+}
+
 impl<'a> TryFrom<&'a ArgMatches<'_>>
     for commands::debugdata::DebugDataCommand<'a>
 {