rhg: refactor relativize_path into a struct + method
authorSimon Sapin <simon.sapin@octobus.net>
Fri, 10 Dec 2021 16:57:39 +0100
changeset 48453 9b0e1f64656f
parent 48452 2afaa0145584
child 48454 473af5cbc209
rhg: refactor relativize_path into a struct + method … instead of a function that takes an iterator and a callback. Differential Revision: https://phab.mercurial-scm.org/D11898
rust/rhg/src/commands/files.rs
rust/rhg/src/commands/status.rs
rust/rhg/src/utils/path_utils.rs
--- a/rust/rhg/src/commands/files.rs	Fri Dec 10 16:31:16 2021 +0100
+++ b/rust/rhg/src/commands/files.rs	Fri Dec 10 16:57:39 2021 +0100
@@ -1,14 +1,12 @@
 use crate::error::CommandError;
 use crate::ui::Ui;
-use crate::ui::UiError;
-use crate::utils::path_utils::relativize_paths;
+use crate::utils::path_utils::RelativizePaths;
 use clap::Arg;
 use hg::errors::HgError;
 use hg::operations::list_rev_tracked_files;
 use hg::operations::Dirstate;
 use hg::repo::Repo;
 use hg::utils::hg_path::HgPath;
-use std::borrow::Cow;
 
 pub const HELP_TEXT: &str = "
 List tracked files.
@@ -86,11 +84,14 @@
     let mut stdout = ui.stdout_buffer();
     let mut any = false;
 
-    relativize_paths(repo, files, |path: Cow<[u8]>| -> Result<(), UiError> {
+    let relativize = RelativizePaths::new(repo)?;
+    for result in files {
+        let path = result?;
+        stdout.write_all(&relativize.relativize(path))?;
+        stdout.write_all(b"\n")?;
         any = true;
-        stdout.write_all(path.as_ref())?;
-        stdout.write_all(b"\n")
-    })?;
+    }
+
     stdout.flush()?;
     if any {
         Ok(())
--- a/rust/rhg/src/commands/status.rs	Fri Dec 10 16:31:16 2021 +0100
+++ b/rust/rhg/src/commands/status.rs	Fri Dec 10 16:57:39 2021 +0100
@@ -7,7 +7,7 @@
 
 use crate::error::CommandError;
 use crate::ui::Ui;
-use crate::utils::path_utils::relativize_paths;
+use crate::utils::path_utils::RelativizePaths;
 use clap::{Arg, SubCommand};
 use format_bytes::format_bytes;
 use hg;
@@ -261,9 +261,12 @@
             .unwrap_or(config.get_bool(b"ui", b"relative-paths")?);
     let output = DisplayStatusPaths {
         ui,
-        repo,
         no_status,
-        relative_paths,
+        relativize: if relative_paths {
+            Some(RelativizePaths::new(repo)?)
+        } else {
+            None
+        },
     };
     if display_states.modified {
         output.display(b"M", ds_status.modified)?;
@@ -379,9 +382,8 @@
 
 struct DisplayStatusPaths<'a> {
     ui: &'a Ui,
-    repo: &'a Repo,
     no_status: bool,
-    relative_paths: bool,
+    relativize: Option<RelativizePaths>,
 }
 
 impl DisplayStatusPaths<'_> {
@@ -393,27 +395,24 @@
         mut paths: Vec<HgPathCow>,
     ) -> Result<(), CommandError> {
         paths.sort_unstable();
-        let print_path = |path: &[u8]| {
+        for path in paths {
+            let relative;
+            let path = if let Some(relativize) = &self.relativize {
+                relative = relativize.relativize(&path);
+                &*relative
+            } else {
+                path.as_bytes()
+            };
             // TODO optim, probably lots of unneeded copies here, especially
             // if out stream is buffered
             if self.no_status {
-                self.ui.write_stdout(&format_bytes!(b"{}\n", path))
+                self.ui.write_stdout(&format_bytes!(b"{}\n", path))?
             } else {
                 self.ui.write_stdout(&format_bytes!(
                     b"{} {}\n",
                     status_prefix,
                     path
-                ))
-            }
-        };
-
-        if self.relative_paths {
-            relativize_paths(self.repo, paths.iter().map(Ok), |path| {
-                print_path(&path)
-            })?;
-        } else {
-            for path in paths {
-                print_path(path.as_bytes())?
+                ))?
             }
         }
         Ok(())
--- a/rust/rhg/src/utils/path_utils.rs	Fri Dec 10 16:31:16 2021 +0100
+++ b/rust/rhg/src/utils/path_utils.rs	Fri Dec 10 16:57:39 2021 +0100
@@ -3,8 +3,6 @@
 // This software may be used and distributed according to the terms of the
 // GNU General Public License version 2 or any later version.
 
-use crate::error::CommandError;
-use crate::ui::UiError;
 use hg::errors::HgError;
 use hg::repo::Repo;
 use hg::utils::current_dir;
@@ -13,37 +11,45 @@
 use hg::utils::hg_path::HgPathBuf;
 use std::borrow::Cow;
 
-pub fn relativize_paths(
-    repo: &Repo,
-    paths: impl IntoIterator<Item = Result<impl AsRef<HgPath>, HgError>>,
-    mut callback: impl FnMut(Cow<[u8]>) -> Result<(), UiError>,
-) -> Result<(), CommandError> {
-    let cwd = current_dir()?;
-    let repo_root = repo.working_directory_path();
-    let repo_root = cwd.join(repo_root); // Make it absolute
-    let repo_root_hgpath =
-        HgPathBuf::from(get_bytes_from_path(repo_root.to_owned()));
-    let outside_repo: bool;
-    let cwd_hgpath: HgPathBuf;
+pub struct RelativizePaths {
+    repo_root: HgPathBuf,
+    cwd: HgPathBuf,
+    outside_repo: bool,
+}
+
+impl RelativizePaths {
+    pub fn new(repo: &Repo) -> Result<Self, HgError> {
+        let cwd = current_dir()?;
+        let repo_root = repo.working_directory_path();
+        let repo_root = cwd.join(repo_root); // Make it absolute
+        let repo_root_hgpath =
+            HgPathBuf::from(get_bytes_from_path(repo_root.to_owned()));
 
-    if let Ok(cwd_relative_to_repo) = cwd.strip_prefix(&repo_root) {
-        // The current directory is inside the repo, so we can work with
-        // relative paths
-        outside_repo = false;
-        cwd_hgpath =
-            HgPathBuf::from(get_bytes_from_path(cwd_relative_to_repo));
-    } else {
-        outside_repo = true;
-        cwd_hgpath = HgPathBuf::from(get_bytes_from_path(cwd));
+        if let Ok(cwd_relative_to_repo) = cwd.strip_prefix(&repo_root) {
+            // The current directory is inside the repo, so we can work with
+            // relative paths
+            Ok(Self {
+                repo_root: repo_root_hgpath,
+                cwd: HgPathBuf::from(get_bytes_from_path(
+                    cwd_relative_to_repo,
+                )),
+                outside_repo: false,
+            })
+        } else {
+            Ok(Self {
+                repo_root: repo_root_hgpath,
+                cwd: HgPathBuf::from(get_bytes_from_path(cwd)),
+                outside_repo: true,
+            })
+        }
     }
 
-    for file in paths {
-        if outside_repo {
-            let file = repo_root_hgpath.join(file?.as_ref());
-            callback(relativize_path(&file, &cwd_hgpath))?;
+    pub fn relativize<'a>(&self, path: &'a HgPath) -> Cow<'a, [u8]> {
+        if self.outside_repo {
+            let joined = self.repo_root.join(path);
+            Cow::Owned(relativize_path(&joined, &self.cwd).into_owned())
         } else {
-            callback(relativize_path(file?.as_ref(), &cwd_hgpath))?;
+            relativize_path(path, &self.cwd)
         }
     }
-    Ok(())
 }