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.
--- 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);
}
}