rhg: Move `Repo` object creation into `main()`
authorSimon Sapin <simon.sapin@octobus.net>
Mon, 15 Feb 2021 20:13:09 +0100
changeset 46593 5ce2aa7c2ad5
parent 46592 80840b651721
child 46594 f88e8ae0aa8f
rhg: Move `Repo` object creation into `main()` … rather than in each sub-command that needs a local repository. This will allow accessing e.g. `.hg/blackbox.log` before dispatching to sub-commands. Differential Revision: https://phab.mercurial-scm.org/D10004
rust/hg-core/src/repo.rs
rust/rhg/src/commands/cat.rs
rust/rhg/src/commands/config.rs
rust/rhg/src/commands/debugdata.rs
rust/rhg/src/commands/debugrequirements.rs
rust/rhg/src/commands/files.rs
rust/rhg/src/commands/root.rs
rust/rhg/src/error.rs
rust/rhg/src/main.rs
--- a/rust/hg-core/src/repo.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/hg-core/src/repo.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -81,28 +81,6 @@
         }
     }
 
-    /// Like `Repo::find`, but not finding a repository is not an error if no
-    /// explicit path is given. `Ok(None)` is returned in that case.
-    ///
-    /// If an explicit path *is* given, not finding a repository there is still
-    /// an error.
-    ///
-    /// For sub-commands that don’t need a repository, configuration should
-    /// still be affected by a repository’s `.hg/hgrc` file. This is the
-    /// constructor to use.
-    pub fn find_optional(
-        config: &Config,
-        explicit_path: Option<&Path>,
-    ) -> Result<Option<Self>, RepoError> {
-        match Self::find(config, explicit_path) {
-            Ok(repo) => Ok(Some(repo)),
-            Err(RepoError::NotFound { .. }) if explicit_path.is_none() => {
-                Ok(None)
-            }
-            Err(error) => Err(error),
-        }
-    }
-
     /// To be called after checking that `.hg` is a sub-directory
     fn new_at_path(
         working_directory: PathBuf,
--- a/rust/rhg/src/commands/cat.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/commands/cat.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -1,7 +1,6 @@
 use crate::error::CommandError;
 use clap::Arg;
 use hg::operations::cat;
-use hg::repo::Repo;
 use hg::utils::hg_path::HgPathBuf;
 use micro_timer::timed;
 use std::convert::TryFrom;
@@ -39,7 +38,7 @@
         None => vec![],
     };
 
-    let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?;
+    let repo = invocation.repo?;
     let cwd = hg::utils::current_dir()?;
 
     let mut files = vec![];
--- a/rust/rhg/src/commands/config.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/commands/config.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -2,7 +2,6 @@
 use clap::Arg;
 use format_bytes::format_bytes;
 use hg::errors::HgError;
-use hg::repo::Repo;
 use hg::utils::SliceExt;
 
 pub const HELP_TEXT: &str = "
@@ -22,13 +21,6 @@
 }
 
 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
-    let opt_repo =
-        Repo::find_optional(invocation.non_repo_config, invocation.repo_path)?;
-    let config = if let Some(repo) = &opt_repo {
-        repo.config()
-    } else {
-        invocation.non_repo_config
-    };
     let (section, name) = invocation
         .subcommand_args
         .value_of("name")
@@ -37,7 +29,7 @@
         .split_2(b'.')
         .ok_or_else(|| HgError::abort(""))?;
 
-    let value = config.get(section, name).unwrap_or(b"");
+    let value = invocation.config().get(section, name).unwrap_or(b"");
 
     invocation.ui.write_stdout(&format_bytes!(b"{}\n", value))?;
     Ok(())
--- a/rust/rhg/src/commands/debugdata.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/commands/debugdata.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -2,7 +2,6 @@
 use clap::Arg;
 use clap::ArgGroup;
 use hg::operations::{debug_data, DebugDataKind};
-use hg::repo::Repo;
 use micro_timer::timed;
 
 pub const HELP_TEXT: &str = "
@@ -55,8 +54,8 @@
             }
         };
 
-    let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?;
-    let data = debug_data(&repo, rev, kind).map_err(|e| (e, rev))?;
+    let repo = invocation.repo?;
+    let data = debug_data(repo, rev, kind).map_err(|e| (e, rev))?;
 
     let mut stdout = invocation.ui.stdout_buffer();
     stdout.write_all(&data)?;
--- a/rust/rhg/src/commands/debugrequirements.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/commands/debugrequirements.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -1,5 +1,4 @@
 use crate::error::CommandError;
-use hg::repo::Repo;
 
 pub const HELP_TEXT: &str = "
 Print the current repo requirements.
@@ -10,7 +9,7 @@
 }
 
 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
-    let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?;
+    let repo = invocation.repo?;
     let mut output = String::new();
     let mut requirements: Vec<_> = repo.requirements().iter().collect();
     requirements.sort();
--- a/rust/rhg/src/commands/files.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/commands/files.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -29,15 +29,14 @@
 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
     let rev = invocation.subcommand_args.value_of("rev");
 
-    let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?;
+    let repo = invocation.repo?;
     if let Some(rev) = rev {
-        let files =
-            list_rev_tracked_files(&repo, rev).map_err(|e| (e, rev))?;
-        display_files(invocation.ui, &repo, files.iter())
+        let files = list_rev_tracked_files(repo, rev).map_err(|e| (e, rev))?;
+        display_files(invocation.ui, repo, files.iter())
     } else {
-        let distate = Dirstate::new(&repo)?;
+        let distate = Dirstate::new(repo)?;
         let files = distate.tracked_files()?;
-        display_files(invocation.ui, &repo, files)
+        display_files(invocation.ui, repo, files)
     }
 }
 
--- a/rust/rhg/src/commands/root.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/commands/root.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -1,6 +1,5 @@
 use crate::error::CommandError;
 use format_bytes::format_bytes;
-use hg::repo::Repo;
 use hg::utils::files::get_bytes_from_path;
 
 pub const HELP_TEXT: &str = "
@@ -14,7 +13,7 @@
 }
 
 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
-    let repo = Repo::find(invocation.non_repo_config, invocation.repo_path)?;
+    let repo = invocation.repo?;
     let bytes = get_bytes_from_path(repo.working_directory_path());
     invocation
         .ui
--- a/rust/rhg/src/error.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/error.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -1,5 +1,6 @@
 use crate::ui::utf8_to_local;
 use crate::ui::UiError;
+use crate::NoRepoInCwdError;
 use format_bytes::format_bytes;
 use hg::config::{ConfigError, ConfigParseError};
 use hg::errors::HgError;
@@ -64,7 +65,7 @@
         match error {
             RepoError::NotFound { at } => CommandError::Abort {
                 message: format_bytes!(
-                    b"no repository found in '{}' (.hg not found)!",
+                    b"repository {} not found",
                     get_bytes_from_path(at)
                 ),
             },
@@ -74,6 +75,18 @@
     }
 }
 
+impl<'a> From<&'a NoRepoInCwdError> for CommandError {
+    fn from(error: &'a NoRepoInCwdError) -> Self {
+        let NoRepoInCwdError { cwd } = error;
+        CommandError::Abort {
+            message: format_bytes!(
+                b"no repository found in '{}' (.hg not found)!",
+                get_bytes_from_path(cwd)
+            ),
+        }
+    }
+}
+
 impl From<ConfigError> for CommandError {
     fn from(error: ConfigError) -> Self {
         match error {
--- a/rust/rhg/src/main.rs	Mon Feb 15 20:05:32 2021 +0100
+++ b/rust/rhg/src/main.rs	Mon Feb 15 20:13:09 2021 +0100
@@ -6,7 +6,8 @@
 use clap::ArgMatches;
 use format_bytes::format_bytes;
 use hg::config::Config;
-use std::path::Path;
+use hg::repo::{Repo, RepoError};
+use std::path::{Path, PathBuf};
 
 mod error;
 mod exitcode;
@@ -74,17 +75,25 @@
     let non_repo_config = &hg::config::Config::load(config_args)?;
 
     let repo_path = value_of_global_arg("repository").map(Path::new);
+    let repo = match Repo::find(non_repo_config, repo_path) {
+        Ok(repo) => Ok(repo),
+        Err(RepoError::NotFound { at }) if repo_path.is_none() => {
+            // Not finding a repo is not fatal yet, if `-R` was not given
+            Err(NoRepoInCwdError { cwd: at })
+        }
+        Err(error) => return Err(error.into()),
+    };
 
     run(&CliInvocation {
         ui,
         subcommand_args,
         non_repo_config,
-        repo_path,
+        repo: repo.as_ref(),
     })
 }
 
 fn main() {
-    let ui = Ui::new();
+    let ui = ui::Ui::new();
 
     let exit_code = match main_with_result(&ui) {
         Ok(()) => exitcode::OK,
@@ -146,5 +155,22 @@
     ui: &'a Ui,
     subcommand_args: &'a ArgMatches<'a>,
     non_repo_config: &'a Config,
-    repo_path: Option<&'a Path>,
+    /// References inside `Result` is a bit peculiar but allow
+    /// `invocation.repo?` to work out with `&CliInvocation` since this
+    /// `Result` type is `Copy`.
+    repo: Result<&'a Repo, &'a NoRepoInCwdError>,
+}
+
+struct NoRepoInCwdError {
+    cwd: PathBuf,
 }
+
+impl CliInvocation<'_> {
+    fn config(&self) -> &Config {
+        if let Ok(repo) = self.repo {
+            repo.config()
+        } else {
+            self.non_repo_config
+        }
+    }
+}