rust/hg-core/src/config/config.rs
changeset 46598 bc08c2331f99
parent 46597 305d74c262de
child 46599 1f55cd5b292f
equal deleted inserted replaced
46597:305d74c262de 46598:bc08c2331f99
     7 // This software may be used and distributed according to the terms of the
     7 // This software may be used and distributed according to the terms of the
     8 // GNU General Public License version 2 or any later version.
     8 // GNU General Public License version 2 or any later version.
     9 
     9 
    10 use super::layer;
    10 use super::layer;
    11 use crate::config::layer::{
    11 use crate::config::layer::{
    12     ConfigError, ConfigLayer, ConfigParseError, ConfigValue,
    12     ConfigError, ConfigLayer, ConfigOrigin, ConfigValue,
    13 };
    13 };
    14 use crate::utils::files::get_bytes_from_os_str;
    14 use crate::utils::files::get_bytes_from_os_str;
    15 use format_bytes::{write_bytes, DisplayBytes};
    15 use format_bytes::{write_bytes, DisplayBytes};
    16 use std::env;
    16 use std::env;
    17 use std::path::{Path, PathBuf};
    17 use std::path::{Path, PathBuf};
    50 pub enum ConfigSource {
    50 pub enum ConfigSource {
    51     /// Absolute path to a config file
    51     /// Absolute path to a config file
    52     AbsPath(PathBuf),
    52     AbsPath(PathBuf),
    53     /// Already parsed (from the CLI, env, Python resources, etc.)
    53     /// Already parsed (from the CLI, env, Python resources, etc.)
    54     Parsed(layer::ConfigLayer),
    54     Parsed(layer::ConfigLayer),
       
    55 }
       
    56 
       
    57 #[derive(Debug)]
       
    58 pub struct ConfigValueParseError {
       
    59     pub origin: ConfigOrigin,
       
    60     pub line: Option<usize>,
       
    61     pub section: Vec<u8>,
       
    62     pub item: Vec<u8>,
       
    63     pub value: Vec<u8>,
       
    64     pub expected_type: &'static str,
    55 }
    65 }
    56 
    66 
    57 pub fn parse_bool(v: &[u8]) -> Option<bool> {
    67 pub fn parse_bool(v: &[u8]) -> Option<bool> {
    58     match v.to_ascii_lowercase().as_slice() {
    68     match v.to_ascii_lowercase().as_slice() {
    59         b"1" | b"yes" | b"true" | b"on" | b"always" => Some(true),
    69         b"1" | b"yes" | b"true" | b"on" | b"always" => Some(true),
   260 
   270 
   261     fn get_parse<'config, T: 'config>(
   271     fn get_parse<'config, T: 'config>(
   262         &'config self,
   272         &'config self,
   263         section: &[u8],
   273         section: &[u8],
   264         item: &[u8],
   274         item: &[u8],
       
   275         expected_type: &'static str,
   265         parse: impl Fn(&'config [u8]) -> Option<T>,
   276         parse: impl Fn(&'config [u8]) -> Option<T>,
   266     ) -> Result<Option<T>, ConfigParseError> {
   277     ) -> Result<Option<T>, ConfigValueParseError> {
   267         match self.get_inner(&section, &item) {
   278         match self.get_inner(&section, &item) {
   268             Some((layer, v)) => match parse(&v.bytes) {
   279             Some((layer, v)) => match parse(&v.bytes) {
   269                 Some(b) => Ok(Some(b)),
   280                 Some(b) => Ok(Some(b)),
   270                 None => Err(ConfigParseError {
   281                 None => Err(ConfigValueParseError {
   271                     origin: layer.origin.to_owned(),
   282                     origin: layer.origin.to_owned(),
   272                     line: v.line,
   283                     line: v.line,
   273                     bytes: v.bytes.to_owned(),
   284                     value: v.bytes.to_owned(),
       
   285                     section: section.to_owned(),
       
   286                     item: item.to_owned(),
       
   287                     expected_type,
   274                 }),
   288                 }),
   275             },
   289             },
   276             None => Ok(None),
   290             None => Ok(None),
   277         }
   291         }
   278     }
   292     }
   281     /// Otherwise, returns an `Ok(value)` if found, or `None`.
   295     /// Otherwise, returns an `Ok(value)` if found, or `None`.
   282     pub fn get_str(
   296     pub fn get_str(
   283         &self,
   297         &self,
   284         section: &[u8],
   298         section: &[u8],
   285         item: &[u8],
   299         item: &[u8],
   286     ) -> Result<Option<&str>, ConfigParseError> {
   300     ) -> Result<Option<&str>, ConfigValueParseError> {
   287         self.get_parse(section, item, |value| str::from_utf8(value).ok())
   301         self.get_parse(section, item, "ASCII or UTF-8 string", |value| {
       
   302             str::from_utf8(value).ok()
       
   303         })
   288     }
   304     }
   289 
   305 
   290     /// Returns an `Err` if the first value found is not a valid unsigned
   306     /// Returns an `Err` if the first value found is not a valid unsigned
   291     /// integer. Otherwise, returns an `Ok(value)` if found, or `None`.
   307     /// integer. Otherwise, returns an `Ok(value)` if found, or `None`.
   292     pub fn get_u32(
   308     pub fn get_u32(
   293         &self,
   309         &self,
   294         section: &[u8],
   310         section: &[u8],
   295         item: &[u8],
   311         item: &[u8],
   296     ) -> Result<Option<u32>, ConfigParseError> {
   312     ) -> Result<Option<u32>, ConfigValueParseError> {
   297         self.get_parse(section, item, |value| {
   313         self.get_parse(section, item, "valid integer", |value| {
   298             str::from_utf8(value).ok()?.parse().ok()
   314             str::from_utf8(value).ok()?.parse().ok()
   299         })
   315         })
   300     }
   316     }
   301 
   317 
   302     /// Returns an `Err` if the first value found is not a valid file size
   318     /// Returns an `Err` if the first value found is not a valid file size
   304     /// Otherwise, returns an `Ok(value_in_bytes)` if found, or `None`.
   320     /// Otherwise, returns an `Ok(value_in_bytes)` if found, or `None`.
   305     pub fn get_byte_size(
   321     pub fn get_byte_size(
   306         &self,
   322         &self,
   307         section: &[u8],
   323         section: &[u8],
   308         item: &[u8],
   324         item: &[u8],
   309     ) -> Result<Option<u64>, ConfigParseError> {
   325     ) -> Result<Option<u64>, ConfigValueParseError> {
   310         self.get_parse(section, item, parse_byte_size)
   326         self.get_parse(section, item, "byte quantity", parse_byte_size)
   311     }
   327     }
   312 
   328 
   313     /// Returns an `Err` if the first value found is not a valid boolean.
   329     /// Returns an `Err` if the first value found is not a valid boolean.
   314     /// Otherwise, returns an `Ok(option)`, where `option` is the boolean if
   330     /// Otherwise, returns an `Ok(option)`, where `option` is the boolean if
   315     /// found, or `None`.
   331     /// found, or `None`.
   316     pub fn get_option(
   332     pub fn get_option(
   317         &self,
   333         &self,
   318         section: &[u8],
   334         section: &[u8],
   319         item: &[u8],
   335         item: &[u8],
   320     ) -> Result<Option<bool>, ConfigParseError> {
   336     ) -> Result<Option<bool>, ConfigValueParseError> {
   321         self.get_parse(section, item, parse_bool)
   337         self.get_parse(section, item, "boolean", parse_bool)
   322     }
   338     }
   323 
   339 
   324     /// Returns the corresponding boolean in the config. Returns `Ok(false)`
   340     /// Returns the corresponding boolean in the config. Returns `Ok(false)`
   325     /// if the value is not found, an `Err` if it's not a valid boolean.
   341     /// if the value is not found, an `Err` if it's not a valid boolean.
   326     pub fn get_bool(
   342     pub fn get_bool(
   327         &self,
   343         &self,
   328         section: &[u8],
   344         section: &[u8],
   329         item: &[u8],
   345         item: &[u8],
   330     ) -> Result<bool, ConfigError> {
   346     ) -> Result<bool, ConfigValueParseError> {
   331         Ok(self.get_option(section, item)?.unwrap_or(false))
   347         Ok(self.get_option(section, item)?.unwrap_or(false))
   332     }
   348     }
   333 
   349 
   334     /// Returns the raw value bytes of the first one found, or `None`.
   350     /// Returns the raw value bytes of the first one found, or `None`.
   335     pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&[u8]> {
   351     pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&[u8]> {