rust/rhg/src/main.rs
changeset 46666 33f2d56acc73
parent 46665 7284b524b441
child 46667 93e9f448273c
--- a/rust/rhg/src/main.rs	Mon Mar 01 13:51:35 2021 +0100
+++ b/rust/rhg/src/main.rs	Mon Mar 01 16:18:42 2021 +0100
@@ -84,8 +84,15 @@
     let ui = ui::Ui::new();
 
     let early_args = EarlyArgs::parse(std::env::args_os());
-    let non_repo_config = Config::load(early_args.config)
-        .unwrap_or_else(|error| exit(&ui, Err(error.into())));
+    let non_repo_config =
+        Config::load(early_args.config).unwrap_or_else(|error| {
+            // Normally this is decided based on config, but we don’t have that
+            // available. As of this writing config loading never returns an
+            // "unsupported" error but that is not enforced by the type system.
+            let on_unsupported = OnUnsupported::Abort;
+
+            exit(&ui, on_unsupported, Err(error.into()))
+        });
 
     let repo_path = early_args.repo.as_deref().map(get_path_from_bytes);
     let repo_result = match Repo::find(&non_repo_config, repo_path) {
@@ -94,7 +101,11 @@
             // Not finding a repo is not fatal yet, if `-R` was not given
             Err(NoRepoInCwdError { cwd: at })
         }
-        Err(error) => exit(&ui, Err(error.into())),
+        Err(error) => exit(
+            &ui,
+            OnUnsupported::from_config(&non_repo_config),
+            Err(error.into()),
+        ),
     };
 
     let config = if let Ok(repo) = &repo_result {
@@ -109,7 +120,7 @@
         repo_result.as_ref(),
         config,
     );
-    exit(&ui, result)
+    exit(&ui, OnUnsupported::from_config(config), result)
 }
 
 fn exit_code(result: &Result<(), CommandError>) -> i32 {
@@ -119,16 +130,37 @@
 
         // Exit with a specific code and no error message to let a potential
         // wrapper script fallback to Python-based Mercurial.
-        Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED,
+        Err(CommandError::UnsupportedFeature { .. }) => {
+            exitcode::UNIMPLEMENTED
+        }
     }
 }
 
-fn exit(ui: &Ui, result: Result<(), CommandError>) -> ! {
-    if let Err(CommandError::Abort { message }) = &result {
-        if !message.is_empty() {
-            // Ignore errors when writing to stderr, we’re already exiting
-            // with failure code so there’s not much more we can do.
-            let _ = ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
+fn exit(
+    ui: &Ui,
+    on_unsupported: OnUnsupported,
+    result: Result<(), CommandError>,
+) -> ! {
+    match &result {
+        Ok(_) => {}
+        Err(CommandError::Abort { message }) => {
+            if !message.is_empty() {
+                // Ignore errors when writing to stderr, we’re already exiting
+                // with failure code so there’s not much more we can do.
+                let _ =
+                    ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
+            }
+        }
+        Err(CommandError::UnsupportedFeature { message }) => {
+            match on_unsupported {
+                OnUnsupported::Abort => {
+                    let _ = ui.write_stderr(&format_bytes!(
+                        b"unsupported feature: {}\n",
+                        message
+                    ));
+                }
+                OnUnsupported::AbortSilent => {}
+            }
         }
     }
     std::process::exit(exit_code(&result))
@@ -226,3 +258,29 @@
         Self { config, repo }
     }
 }
+
+/// What to do when encountering some unsupported feature.
+///
+/// See `HgError::UnsupportedFeature` and `CommandError::UnsupportedFeature`.
+enum OnUnsupported {
+    /// Print an error message describing what feature is not supported,
+    /// and exit with code 252.
+    Abort,
+    /// Silently exit with code 252.
+    AbortSilent,
+}
+
+impl OnUnsupported {
+    fn from_config(config: &Config) -> Self {
+        let default = OnUnsupported::Abort;
+        match config.get(b"rhg", b"on-unsupported") {
+            Some(b"abort") => OnUnsupported::Abort,
+            Some(b"abort-silent") => OnUnsupported::AbortSilent,
+            None => default,
+            Some(_) => {
+                // TODO: warn about unknown config value
+                default
+            }
+        }
+    }
+}