Patchwork D10188: rhg: Add an allow-list of ignored extensions

login
register
mail settings
Submitter phabricator
Date March 12, 2021, 10:08 p.m.
Message ID <differential-rev-PHID-DREV-seiljx3gobta5hybooae-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/48503/
State Superseded
Headers show

Comments

phabricator - March 12, 2021, 10:08 p.m.
SimonSapin created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Because rhg doesn’t know how a Python extension would affect
  behavior it implements in Rust, when an unsupported extension
  is enabled it conservatively falls back to Python-based hg.
  
  However many users will have unsupported extensions enabled in practice.
  Maybe they don’t actually affect rhg behavior, but we don’t know.
  This adds a `rhg.ignored-extensions` configuration that lets
  users list extensions that rhg can safely ignore and proceed even
  if they’re not supported in Rust.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D10188

AFFECTED FILES
  rust/hg-core/src/config/config.rs
  rust/rhg/src/main.rs

CHANGE DETAILS




To: SimonSapin, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs
--- a/rust/rhg/src/main.rs
+++ b/rust/rhg/src/main.rs
@@ -365,12 +365,20 @@ 
         unsupported.remove(supported);
     }
 
+    if let Some(ignored_list) =
+        config.get_simple_list(b"rhg", b"ignored-extensions")
+    {
+        for ignored in ignored_list {
+            unsupported.remove(ignored);
+        }
+    }
+
     if unsupported.is_empty() {
         Ok(())
     } else {
         Err(CommandError::UnsupportedFeature {
             message: format_bytes!(
-                b"extensions: {}",
+                b"extensions: {}.\nConsider adding them to 'rhg.ignored-extensions' config.",
                 join(unsupported, b", ")
             ),
         })
diff --git a/rust/hg-core/src/config/config.rs b/rust/hg-core/src/config/config.rs
--- a/rust/hg-core/src/config/config.rs
+++ b/rust/hg-core/src/config/config.rs
@@ -13,6 +13,7 @@ 
     ConfigError, ConfigLayer, ConfigOrigin, ConfigValue,
 };
 use crate::utils::files::get_bytes_from_os_str;
+use crate::utils::SliceExt;
 use format_bytes::{write_bytes, DisplayBytes};
 use std::collections::HashSet;
 use std::env;
@@ -339,6 +340,31 @@ 
         Ok(self.get_option(section, item)?.unwrap_or(false))
     }
 
+    /// Returns the corresponding list-value in the config if found, or `None`.
+    ///
+    /// This is appropriate for new configuration keys. The value syntax is
+    /// **not** the same as most existing list-valued config, which has Python
+    /// parsing implemented in `parselist()` in `mercurial/config.py`.
+    /// Faithfully porting that parsing algorithm to Rust (including behavior
+    /// that are arguably bugs) turned out to be non-trivial and hasn’t been
+    /// completed as of this writing.
+    ///
+    /// Instead, the "simple" syntax is: split on comma, then trim leading and
+    /// trailing whitespace of each component. Quotes or backslashes are not
+    /// interpreted in any way. Commas are mandatory between values. Values
+    /// that contain a comma are not supported.
+    pub fn get_simple_list(
+        &self,
+        section: &[u8],
+        item: &[u8],
+    ) -> Option<impl Iterator<Item = &[u8]>> {
+        self.get(section, item).map(|value| {
+            value
+                .split(|&byte| byte == b',')
+                .map(|component| component.trim())
+        })
+    }
+
     /// Returns the raw value bytes of the first one found, or `None`.
     pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&[u8]> {
         self.get_inner(section, item)