rust-config: fix fallback to default not parsing the default value
authorRaphaël Gomès <rgomes@octobus.net>
Wed, 09 Aug 2023 15:41:18 +0200
changeset 50981 58390f59826f
parent 50980 d7b2701f17fa
child 50982 10e57e3f7276
rust-config: fix fallback to default not parsing the default value When a config item's default is a string, it sometimes needs to be parsed into another type, like in the case of `cmdserver.max-log-size`, that returns a number of bytes from a human-readable amount like `25MB`. The logic for the fix is explained inline.
rust/hg-core/src/config/config_items.rs
rust/hg-core/src/config/mod.rs
--- a/rust/hg-core/src/config/config_items.rs	Tue Aug 08 14:14:00 2023 +0200
+++ b/rust/hg-core/src/config/config_items.rs	Wed Aug 09 15:41:18 2023 +0200
@@ -140,6 +140,39 @@
     }
 }
 
+impl<'a> TryFrom<&'a DefaultConfigItem> for Option<&'a [u8]> {
+    type Error = HgError;
+
+    fn try_from(
+        value: &'a DefaultConfigItem,
+    ) -> Result<Option<&'a [u8]>, Self::Error> {
+        match &value.default {
+            Some(default) => {
+                let err = HgError::abort(
+                    format!(
+                        "programming error: wrong query on config item '{}.{}'",
+                        value.section,
+                        value.name
+                    ),
+                    exit_codes::ABORT,
+                    Some(format!(
+                        "asked for bytes, type of default is '{}', \
+                        which cannot be interpreted as bytes",
+                        default.type_str()
+                    )),
+                );
+                match default {
+                    DefaultConfigItemType::Primitive(p) => {
+                        Ok(p.as_str().map(str::as_bytes))
+                    }
+                    _ => Err(err),
+                }
+            }
+            None => Ok(None),
+        }
+    }
+}
+
 impl TryFrom<&DefaultConfigItem> for Option<bool> {
     type Error = HgError;
 
--- a/rust/hg-core/src/config/mod.rs	Tue Aug 08 14:14:00 2023 +0200
+++ b/rust/hg-core/src/config/mod.rs	Wed Aug 09 15:41:18 2023 +0200
@@ -422,7 +422,30 @@
                     return Ok(None);
                 }
                 match self.get_default(section, item)? {
-                    Some(default) => Ok(default.try_into()?),
+                    Some(default) => {
+                        // Defaults are TOML values, so they're not in the same
+                        // shape as in the config files.
+                        // First try to convert directly to the expected type
+                        let as_t = default.try_into();
+                        match as_t {
+                            Ok(t) => Ok(t),
+                            Err(e) => {
+                                // If it fails, it means that...
+                                let as_bytes: Result<Option<&[u8]>, _> =
+                                    default.try_into();
+                                match as_bytes {
+                                    Ok(bytes_opt) => {
+                                        if let Some(bytes) = bytes_opt {
+                                            // ...we should be able to parse it
+                                            return Ok(parse(bytes));
+                                        }
+                                        Err(e)
+                                    }
+                                    Err(_) => Err(e),
+                                }
+                            }
+                        }
+                    }
                     None => {
                         self.print_devel_warning(section, item)?;
                         Ok(None)
@@ -779,7 +802,6 @@
         let config = Config::load_from_explicit_sources(vec![])
             .expect("expected valid config");
         let ret = config.get_byte_size(b"cmdserver", b"max-log-size");
-        // FIXME should be `is_ok`
-        assert!(ret.is_err(), "{:?}", ret);
+        assert!(ret.is_ok(), "{:?}", ret);
     }
 }