Details
Details
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Lint
Automatic diff as part of commit; lint not applicable. - Unit
Automatic diff as part of commit; unit tests not applicable.
( )
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
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) |
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() | |||||
} |