Show More
@@ -15,6 +15,7 use crate::utils::files::get_bytes_from_ | |||
|
15 | 15 | use format_bytes::{write_bytes, DisplayBytes}; |
|
16 | 16 | use std::env; |
|
17 | 17 | use std::path::{Path, PathBuf}; |
|
18 | use std::str; | |
|
18 | 19 | |
|
19 | 20 | use crate::errors::{HgResultExt, IoResultExt}; |
|
20 | 21 | |
@@ -61,6 +62,32 pub fn parse_bool(v: &[u8]) -> Option<bo | |||
|
61 | 62 | } |
|
62 | 63 | } |
|
63 | 64 | |
|
65 | pub fn parse_byte_size(value: &[u8]) -> Option<u64> { | |
|
66 | let value = str::from_utf8(value).ok()?.to_ascii_lowercase(); | |
|
67 | const UNITS: &[(&str, u64)] = &[ | |
|
68 | ("g", 1 << 30), | |
|
69 | ("gb", 1 << 30), | |
|
70 | ("m", 1 << 20), | |
|
71 | ("mb", 1 << 20), | |
|
72 | ("k", 1 << 10), | |
|
73 | ("kb", 1 << 10), | |
|
74 | ("b", 1 << 0), // Needs to be last | |
|
75 | ]; | |
|
76 | for &(unit, multiplier) in UNITS { | |
|
77 | // TODO: use `value.strip_suffix(unit)` when we require Rust 1.45+ | |
|
78 | if value.ends_with(unit) { | |
|
79 | let value_before_unit = &value[..value.len() - unit.len()]; | |
|
80 | let float: f64 = value_before_unit.trim().parse().ok()?; | |
|
81 | if float >= 0.0 { | |
|
82 | return Some((float * multiplier as f64).round() as u64); | |
|
83 | } else { | |
|
84 | return None; | |
|
85 | } | |
|
86 | } | |
|
87 | } | |
|
88 | value.parse().ok() | |
|
89 | } | |
|
90 | ||
|
64 | 91 | impl Config { |
|
65 | 92 | /// Load system and user configuration from various files. |
|
66 | 93 | /// |
@@ -231,16 +258,14 impl Config { | |||
|
231 | 258 | Ok(repo_config) |
|
232 | 259 | } |
|
233 | 260 | |
|
234 | /// Returns an `Err` if the first value found is not a valid boolean. | |
|
235 | /// Otherwise, returns an `Ok(option)`, where `option` is the boolean if | |
|
236 | /// found, or `None`. | |
|
237 | pub fn get_option( | |
|
238 | &self, | |
|
261 | fn get_parse<'config, T: 'config>( | |
|
262 | &'config self, | |
|
239 | 263 | section: &[u8], |
|
240 | 264 | item: &[u8], |
|
241 | ) -> Result<Option<bool>, ConfigParseError> { | |
|
265 | parse: impl Fn(&'config [u8]) -> Option<T>, | |
|
266 | ) -> Result<Option<T>, ConfigParseError> { | |
|
242 | 267 | match self.get_inner(§ion, &item) { |
|
243 |
Some((layer, v)) => match parse |
|
|
268 | Some((layer, v)) => match parse(&v.bytes) { | |
|
244 | 269 | Some(b) => Ok(Some(b)), |
|
245 | 270 | None => Err(ConfigParseError { |
|
246 | 271 | origin: layer.origin.to_owned(), |
@@ -252,6 +277,50 impl Config { | |||
|
252 | 277 | } |
|
253 | 278 | } |
|
254 | 279 | |
|
280 | /// Returns an `Err` if the first value found is not a valid UTF-8 string. | |
|
281 | /// Otherwise, returns an `Ok(value)` if found, or `None`. | |
|
282 | pub fn get_str( | |
|
283 | &self, | |
|
284 | section: &[u8], | |
|
285 | item: &[u8], | |
|
286 | ) -> Result<Option<&str>, ConfigParseError> { | |
|
287 | self.get_parse(section, item, |value| str::from_utf8(value).ok()) | |
|
288 | } | |
|
289 | ||
|
290 | /// Returns an `Err` if the first value found is not a valid unsigned | |
|
291 | /// integer. Otherwise, returns an `Ok(value)` if found, or `None`. | |
|
292 | pub fn get_u32( | |
|
293 | &self, | |
|
294 | section: &[u8], | |
|
295 | item: &[u8], | |
|
296 | ) -> Result<Option<u32>, ConfigParseError> { | |
|
297 | self.get_parse(section, item, |value| { | |
|
298 | str::from_utf8(value).ok()?.parse().ok() | |
|
299 | }) | |
|
300 | } | |
|
301 | ||
|
302 | /// Returns an `Err` if the first value found is not a valid file size | |
|
303 | /// value such as `30` (default unit is bytes), `7 MB`, or `42.5 kb`. | |
|
304 | /// Otherwise, returns an `Ok(value_in_bytes)` if found, or `None`. | |
|
305 | pub fn get_byte_size( | |
|
306 | &self, | |
|
307 | section: &[u8], | |
|
308 | item: &[u8], | |
|
309 | ) -> Result<Option<u64>, ConfigParseError> { | |
|
310 | self.get_parse(section, item, parse_byte_size) | |
|
311 | } | |
|
312 | ||
|
313 | /// 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 | |
|
315 | /// found, or `None`. | |
|
316 | pub fn get_option( | |
|
317 | &self, | |
|
318 | section: &[u8], | |
|
319 | item: &[u8], | |
|
320 | ) -> Result<Option<bool>, ConfigParseError> { | |
|
321 | self.get_parse(section, item, parse_bool) | |
|
322 | } | |
|
323 | ||
|
255 | 324 | /// Returns the corresponding boolean in the config. Returns `Ok(false)` |
|
256 | 325 | /// if the value is not found, an `Err` if it's not a valid boolean. |
|
257 | 326 | pub fn get_bool( |
@@ -317,7 +386,8 mod tests { | |||
|
317 | 386 | let base_config_path = tmpdir_path.join("base.rc"); |
|
318 | 387 | let mut config_file = File::create(&base_config_path).unwrap(); |
|
319 | 388 | let data = |
|
320 |
b"[section]\nitem=value0\n%include included.rc\nitem=value2 |
|
|
389 | b"[section]\nitem=value0\n%include included.rc\nitem=value2\n\ | |
|
390 | [section2]\ncount = 4\nsize = 1.5 KB\nnot-count = 1.5\nnot-size = 1 ub"; | |
|
321 | 391 | config_file.write_all(data).unwrap(); |
|
322 | 392 | |
|
323 | 393 | let sources = vec![ConfigSource::AbsPath(base_config_path)]; |
@@ -339,5 +409,13 mod tests { | |||
|
339 | 409 | config.get_all(b"section", b"item"), |
|
340 | 410 | [b"value2", b"value1", b"value0"] |
|
341 | 411 | ); |
|
412 | ||
|
413 | assert_eq!(config.get_u32(b"section2", b"count").unwrap(), Some(4)); | |
|
414 | assert_eq!( | |
|
415 | config.get_byte_size(b"section2", b"size").unwrap(), | |
|
416 | Some(1024 + 512) | |
|
417 | ); | |
|
418 | assert!(config.get_u32(b"section2", b"not-count").is_err()); | |
|
419 | assert!(config.get_byte_size(b"section2", b"not-size").is_err()); | |
|
342 | 420 | } |
|
343 | 421 | } |
General Comments 0
You need to be logged in to leave comments.
Login now