rhg: support rhg files [FILE]
authorSpencer Baugh <sbaugh@janestreet.com>
Thu, 17 Aug 2023 15:53:32 -0400
changeset 50867 788113f056d4
parent 50866 c112cc9effdc
child 50869 e0cae2b44191
rhg: support rhg files [FILE] This comes mostly for free after the rhg status [FILE] implementation.
rust/rhg/src/commands/files.rs
--- a/rust/rhg/src/commands/files.rs	Wed Aug 02 10:46:47 2023 -0400
+++ b/rust/rhg/src/commands/files.rs	Thu Aug 17 15:53:32 2023 -0400
@@ -4,9 +4,12 @@
 };
 use crate::utils::path_utils::RelativizePaths;
 use clap::Arg;
+use hg::filepatterns::parse_pattern_args;
+use hg::matchers::IntersectionMatcher;
 use hg::narrow;
 use hg::operations::list_rev_tracked_files;
 use hg::repo::Repo;
+use hg::utils::files::get_bytes_from_os_str;
 use hg::utils::filter_map_results;
 use hg::utils::hg_path::HgPath;
 use rayon::prelude::*;
@@ -26,6 +29,12 @@
                 .long("revision")
                 .value_name("REV"),
         )
+        .arg(
+            Arg::new("file")
+                .value_parser(clap::value_parser!(std::ffi::OsString))
+                .help("show only these files")
+                .action(clap::ArgAction::Append),
+        )
         .about(HELP_TEXT)
 }
 
@@ -35,7 +44,8 @@
         RelativePaths::Bool(v) => v,
     };
 
-    let rev = invocation.subcommand_args.get_one::<String>("rev");
+    let args = invocation.subcommand_args;
+    let rev = args.get_one::<String>("rev");
 
     let repo = invocation.repo?;
 
@@ -51,11 +61,34 @@
         ));
     }
 
-    let (narrow_matcher, narrow_warnings) = narrow::matcher(repo)?;
+    let (matcher, narrow_warnings) = narrow::matcher(repo)?;
     print_narrow_sparse_warnings(&narrow_warnings, &[], invocation.ui, repo)?;
+    let matcher = match args.get_many::<std::ffi::OsString>("file") {
+        None => matcher,
+        Some(files) => {
+            let patterns: Vec<Vec<u8>> = files
+                .filter(|s| !s.is_empty())
+                .map(get_bytes_from_os_str)
+                .collect();
+            for file in &patterns {
+                if file.starts_with(b"set:") {
+                    return Err(CommandError::unsupported("fileset"));
+                }
+            }
+            let cwd = hg::utils::current_dir()?;
+            let root = repo.working_directory_path();
+            let ignore_patterns = parse_pattern_args(patterns, &cwd, root)?;
+            let files_matcher =
+                hg::matchers::PatternMatcher::new(ignore_patterns)?;
+            Box::new(IntersectionMatcher::new(
+                Box::new(files_matcher),
+                matcher,
+            ))
+        }
+    };
 
     if let Some(rev) = rev {
-        let files = list_rev_tracked_files(repo, rev, narrow_matcher)
+        let files = list_rev_tracked_files(repo, rev, matcher)
             .map_err(|e| (e, rev.as_ref()))?;
         display_files(invocation.ui, repo, relative_paths, files.iter())
     } else {
@@ -63,7 +96,7 @@
         let dirstate = repo.dirstate_map()?;
         let files_res: Result<Vec<_>, _> =
             filter_map_results(dirstate.iter(), |(path, entry)| {
-                Ok(if entry.tracked() && narrow_matcher.matches(path) {
+                Ok(if entry.tracked() && matcher.matches(path) {
                     Some(path)
                 } else {
                     None