Details
Details
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
( )
| No Linters Available |
| No Unit Test Coverage |
| Path | Packages | |||
|---|---|---|---|---|
| M | rust/hg-core/src/config.rs (1 line) | |||
| M | rust/hg-core/src/config/config.rs (39 lines) | |||
| A | M | rust/hg-core/src/config/values.rs (43 lines) |
| Commit | Parents | Author | Summary | Date |
|---|---|---|---|---|
| 1fe30b20c2a1 | 9dec02ee2bc6 | Simon Sapin | Feb 17 2021, 2:24 PM |
| Status | Author | Revision | |
|---|---|---|---|
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin |
| // config.rs | // config.rs | ||||
| // | // | ||||
| // Copyright 2020 | // Copyright 2020 | ||||
| // Valentin Gatien-Baron, | // Valentin Gatien-Baron, | ||||
| // Raphaël Gomès <rgomes@octobus.net> | // Raphaël Gomès <rgomes@octobus.net> | ||||
| // | // | ||||
| // This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
| // GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
| //! Mercurial config parsing and interfaces. | //! Mercurial config parsing and interfaces. | ||||
| mod config; | mod config; | ||||
| mod layer; | mod layer; | ||||
| mod values; | |||||
| pub use config::{Config, ConfigValueParseError}; | pub use config::{Config, ConfigValueParseError}; | ||||
| pub use layer::{ConfigError, ConfigParseError}; | pub use layer::{ConfigError, ConfigParseError}; | ||||
| // config.rs | // config.rs | ||||
| // | // | ||||
| // Copyright 2020 | // Copyright 2020 | ||||
| // Valentin Gatien-Baron, | // Valentin Gatien-Baron, | ||||
| // Raphaël Gomès <rgomes@octobus.net> | // Raphaël Gomès <rgomes@octobus.net> | ||||
| // | // | ||||
| // This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
| // GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
| use super::layer; | use super::layer; | ||||
| use super::values; | |||||
| use crate::config::layer::{ | use crate::config::layer::{ | ||||
| ConfigError, ConfigLayer, ConfigOrigin, ConfigValue, | ConfigError, ConfigLayer, ConfigOrigin, ConfigValue, | ||||
| }; | }; | ||||
| use crate::utils::files::get_bytes_from_os_str; | use crate::utils::files::get_bytes_from_os_str; | ||||
| use format_bytes::{write_bytes, DisplayBytes}; | use format_bytes::{write_bytes, DisplayBytes}; | ||||
| use std::env; | use std::env; | ||||
| use std::path::{Path, PathBuf}; | use std::path::{Path, PathBuf}; | ||||
| use std::str; | use std::str; | ||||
| pub origin: ConfigOrigin, | pub origin: ConfigOrigin, | ||||
| pub line: Option<usize>, | pub line: Option<usize>, | ||||
| pub section: Vec<u8>, | pub section: Vec<u8>, | ||||
| pub item: Vec<u8>, | pub item: Vec<u8>, | ||||
| pub value: Vec<u8>, | pub value: Vec<u8>, | ||||
| pub expected_type: &'static str, | pub expected_type: &'static str, | ||||
| } | } | ||||
| pub fn parse_bool(v: &[u8]) -> Option<bool> { | |||||
| match v.to_ascii_lowercase().as_slice() { | |||||
| b"1" | b"yes" | b"true" | b"on" | b"always" => Some(true), | |||||
| b"0" | b"no" | b"false" | b"off" | b"never" => Some(false), | |||||
| _ => None, | |||||
| } | |||||
| } | |||||
| pub fn parse_byte_size(value: &[u8]) -> Option<u64> { | |||||
| let value = str::from_utf8(value).ok()?.to_ascii_lowercase(); | |||||
| const UNITS: &[(&str, u64)] = &[ | |||||
| ("g", 1 << 30), | |||||
| ("gb", 1 << 30), | |||||
| ("m", 1 << 20), | |||||
| ("mb", 1 << 20), | |||||
| ("k", 1 << 10), | |||||
| ("kb", 1 << 10), | |||||
| ("b", 1 << 0), // Needs to be last | |||||
| ]; | |||||
| for &(unit, multiplier) in UNITS { | |||||
| // TODO: use `value.strip_suffix(unit)` when we require Rust 1.45+ | |||||
| if value.ends_with(unit) { | |||||
| let value_before_unit = &value[..value.len() - unit.len()]; | |||||
| let float: f64 = value_before_unit.trim().parse().ok()?; | |||||
| if float >= 0.0 { | |||||
| return Some((float * multiplier as f64).round() as u64); | |||||
| } else { | |||||
| return None; | |||||
| } | |||||
| } | |||||
| } | |||||
| value.parse().ok() | |||||
| } | |||||
| impl Config { | impl Config { | ||||
| /// Load system and user configuration from various files. | /// Load system and user configuration from various files. | ||||
| /// | /// | ||||
| /// This is also affected by some environment variables. | /// This is also affected by some environment variables. | ||||
| pub fn load( | pub fn load( | ||||
| cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>, | cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>, | ||||
| ) -> Result<Self, ConfigError> { | ) -> Result<Self, ConfigError> { | ||||
| let mut config = Self { layers: Vec::new() }; | let mut config = Self { layers: Vec::new() }; | ||||
| /// Returns an `Err` if the first value found is not a valid file size | /// Returns an `Err` if the first value found is not a valid file size | ||||
| /// value such as `30` (default unit is bytes), `7 MB`, or `42.5 kb`. | /// value such as `30` (default unit is bytes), `7 MB`, or `42.5 kb`. | ||||
| /// Otherwise, returns an `Ok(value_in_bytes)` if found, or `None`. | /// Otherwise, returns an `Ok(value_in_bytes)` if found, or `None`. | ||||
| pub fn get_byte_size( | pub fn get_byte_size( | ||||
| &self, | &self, | ||||
| section: &[u8], | section: &[u8], | ||||
| item: &[u8], | item: &[u8], | ||||
| ) -> Result<Option<u64>, ConfigValueParseError> { | ) -> Result<Option<u64>, ConfigValueParseError> { | ||||
| self.get_parse(section, item, "byte quantity", parse_byte_size) | self.get_parse(section, item, "byte quantity", values::parse_byte_size) | ||||
| } | } | ||||
| /// Returns an `Err` if the first value found is not a valid boolean. | /// Returns an `Err` if the first value found is not a valid boolean. | ||||
| /// Otherwise, returns an `Ok(option)`, where `option` is the boolean if | /// Otherwise, returns an `Ok(option)`, where `option` is the boolean if | ||||
| /// found, or `None`. | /// found, or `None`. | ||||
| pub fn get_option( | pub fn get_option( | ||||
| &self, | &self, | ||||
| section: &[u8], | section: &[u8], | ||||
| item: &[u8], | item: &[u8], | ||||
| ) -> Result<Option<bool>, ConfigValueParseError> { | ) -> Result<Option<bool>, ConfigValueParseError> { | ||||
| self.get_parse(section, item, "boolean", parse_bool) | self.get_parse(section, item, "boolean", values::parse_bool) | ||||
| } | } | ||||
| /// Returns the corresponding boolean in the config. Returns `Ok(false)` | /// Returns the corresponding boolean in the config. Returns `Ok(false)` | ||||
| /// if the value is not found, an `Err` if it's not a valid boolean. | /// if the value is not found, an `Err` if it's not a valid boolean. | ||||
| pub fn get_bool( | pub fn get_bool( | ||||
| &self, | &self, | ||||
| section: &[u8], | section: &[u8], | ||||
| item: &[u8], | item: &[u8], | ||||
| //! Parsing functions for various type of configuration values. | |||||
| //! | |||||
| //! Returning `None` indicates a syntax error. Using a `Result` would be more | |||||
| //! correct but would take more boilerplate for converting between error types, | |||||
| //! compared to using `.ok()` on inner results of various error types to | |||||
| //! convert them all to options. The `Config::get_parse` method later converts | |||||
| //! those options to results with `ConfigValueParseError`, which contains | |||||
| //! details about where the value came from (but omits details of what’s | |||||
| //! invalid inside the value). | |||||
| pub(super) fn parse_bool(v: &[u8]) -> Option<bool> { | |||||
| match v.to_ascii_lowercase().as_slice() { | |||||
| b"1" | b"yes" | b"true" | b"on" | b"always" => Some(true), | |||||
| b"0" | b"no" | b"false" | b"off" | b"never" => Some(false), | |||||
| _ => None, | |||||
| } | |||||
| } | |||||
| pub(super) fn parse_byte_size(value: &[u8]) -> Option<u64> { | |||||
| let value = std::str::from_utf8(value).ok()?.to_ascii_lowercase(); | |||||
| const UNITS: &[(&str, u64)] = &[ | |||||
| ("g", 1 << 30), | |||||
| ("gb", 1 << 30), | |||||
| ("m", 1 << 20), | |||||
| ("mb", 1 << 20), | |||||
| ("k", 1 << 10), | |||||
| ("kb", 1 << 10), | |||||
| ("b", 1 << 0), // Needs to be last | |||||
| ]; | |||||
| for &(unit, multiplier) in UNITS { | |||||
| // TODO: use `value.strip_suffix(unit)` when we require Rust 1.45+ | |||||
| if value.ends_with(unit) { | |||||
| let value_before_unit = &value[..value.len() - unit.len()]; | |||||
| let float: f64 = value_before_unit.trim().parse().ok()?; | |||||
| if float >= 0.0 { | |||||
| return Some((float * multiplier as f64).round() as u64); | |||||
| } else { | |||||
| return None; | |||||
| } | |||||
| } | |||||
| } | |||||
| value.parse().ok() | |||||
| } | |||||