mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-26 14:10:19 +00:00
feature: support human times for default_time_value
and time_delta
(#1172)
* feature: support human times for time interval and default range * add tests, fix not using ms * appease clippy * changelog
This commit is contained in:
parent
6b9663a2c2
commit
eccaf11937
4 changed files with 157 additions and 21 deletions
|
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.9.2] - Unreleased
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [#1172](https://github.com/ClementTsang/bottom/pull/1172): Support human times for `time_delta` and `default_time_value`.
|
||||||
|
|
||||||
## [0.9.1] - 2023-05-14
|
## [0.9.1] - 2023-05-14
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -136,7 +136,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bottom"
|
name = "bottom"
|
||||||
version = "0.9.1"
|
version = "0.9.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bottom"
|
name = "bottom"
|
||||||
version = "0.9.1"
|
version = "0.9.2"
|
||||||
authors = ["Clement Tsang <cjhtsang@uwaterloo.ca>"]
|
authors = ["Clement Tsang <cjhtsang@uwaterloo.ca>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/ClementTsang/bottom"
|
repository = "https://github.com/ClementTsang/bottom"
|
||||||
|
|
168
src/options.rs
168
src/options.rs
|
@ -57,8 +57,8 @@ pub struct ConfigFlags {
|
||||||
pub whole_word: Option<bool>,
|
pub whole_word: Option<bool>,
|
||||||
pub regex: Option<bool>,
|
pub regex: Option<bool>,
|
||||||
pub basic: Option<bool>,
|
pub basic: Option<bool>,
|
||||||
pub default_time_value: Option<u64>,
|
pub default_time_value: Option<String>,
|
||||||
pub time_delta: Option<u64>,
|
pub time_delta: Option<String>,
|
||||||
pub autohide_time: Option<bool>,
|
pub autohide_time: Option<bool>,
|
||||||
pub hide_time: Option<bool>,
|
pub hide_time: Option<bool>,
|
||||||
pub default_widget_type: Option<String>,
|
pub default_widget_type: Option<String>,
|
||||||
|
@ -582,20 +582,27 @@ fn get_show_average_cpu(matches: &ArgMatches, config: &Config) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: Let this accept human times.
|
fn try_parse_ms(s: &str) -> error::Result<u64> {
|
||||||
|
if let Ok(val) = humantime::parse_duration(s) {
|
||||||
|
Ok(val.as_millis().try_into()?)
|
||||||
|
} else if let Ok(val) = s.parse::<u64>() {
|
||||||
|
Ok(val)
|
||||||
|
} else {
|
||||||
|
Err(BottomError::ConfigError(
|
||||||
|
"could not parse as a valid 64-bit unsigned integer or a human time".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_default_time_value(
|
fn get_default_time_value(
|
||||||
matches: &ArgMatches, config: &Config, retention_ms: u64,
|
matches: &ArgMatches, config: &Config, retention_ms: u64,
|
||||||
) -> error::Result<u64> {
|
) -> error::Result<u64> {
|
||||||
let default_time =
|
let default_time =
|
||||||
if let Some(default_time_value) = matches.get_one::<String>("default_time_value") {
|
if let Some(default_time_value) = matches.get_one::<String>("default_time_value") {
|
||||||
default_time_value.parse::<u64>().map_err(|_| {
|
try_parse_ms(default_time_value)?
|
||||||
BottomError::ConfigError(
|
|
||||||
"could not parse as a valid 64-bit unsigned integer".to_string(),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
} else if let Some(flags) = &config.flags {
|
} else if let Some(flags) = &config.flags {
|
||||||
if let Some(default_time_value) = flags.default_time_value {
|
if let Some(default_time_value) = &flags.default_time_value {
|
||||||
default_time_value
|
try_parse_ms(default_time_value)?
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_TIME_MILLISECONDS
|
DEFAULT_TIME_MILLISECONDS
|
||||||
}
|
}
|
||||||
|
@ -621,14 +628,10 @@ fn get_time_interval(
|
||||||
matches: &ArgMatches, config: &Config, retention_ms: u64,
|
matches: &ArgMatches, config: &Config, retention_ms: u64,
|
||||||
) -> error::Result<u64> {
|
) -> error::Result<u64> {
|
||||||
let time_interval = if let Some(time_interval) = matches.get_one::<String>("time_delta") {
|
let time_interval = if let Some(time_interval) = matches.get_one::<String>("time_delta") {
|
||||||
time_interval.parse::<u64>().map_err(|_| {
|
try_parse_ms(time_interval)?
|
||||||
BottomError::ConfigError(
|
|
||||||
"could not parse as a valid 64-bit unsigned integer".to_string(),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
} else if let Some(flags) = &config.flags {
|
} else if let Some(flags) = &config.flags {
|
||||||
if let Some(time_interval) = flags.time_delta {
|
if let Some(time_interval) = &flags.time_delta {
|
||||||
time_interval
|
try_parse_ms(time_interval)?
|
||||||
} else {
|
} else {
|
||||||
TIME_CHANGE_MILLISECONDS
|
TIME_CHANGE_MILLISECONDS
|
||||||
}
|
}
|
||||||
|
@ -869,8 +872,135 @@ fn get_retention_ms(matches: &ArgMatches, config: &Config) -> error::Result<u64>
|
||||||
mod test {
|
mod test {
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
|
||||||
use super::{get_color_scheme, get_widget_layout, Config};
|
use super::{get_color_scheme, get_time_interval, get_widget_layout, Config};
|
||||||
use crate::{app::App, canvas::canvas_styling::CanvasStyling};
|
use crate::{
|
||||||
|
app::App,
|
||||||
|
canvas::canvas_styling::CanvasStyling,
|
||||||
|
options::{get_default_time_value, try_parse_ms, ConfigFlags},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_try_parse_ms() {
|
||||||
|
let a = "100s";
|
||||||
|
let b = "100";
|
||||||
|
let c = "1 min";
|
||||||
|
let d = "1 hour 1 min";
|
||||||
|
|
||||||
|
assert_eq!(try_parse_ms(a), Ok(100 * 1000));
|
||||||
|
assert_eq!(try_parse_ms(b), Ok(100));
|
||||||
|
assert_eq!(try_parse_ms(c), Ok(60 * 1000));
|
||||||
|
assert_eq!(try_parse_ms(d), Ok(3660 * 1000));
|
||||||
|
|
||||||
|
let a_bad = "1 test";
|
||||||
|
let b_bad = "-100";
|
||||||
|
|
||||||
|
assert!(try_parse_ms(a_bad).is_err());
|
||||||
|
assert!(try_parse_ms(b_bad).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn matches_human_times() {
|
||||||
|
let config = Config::default();
|
||||||
|
let app = crate::clap::build_app();
|
||||||
|
|
||||||
|
{
|
||||||
|
let app = app.clone();
|
||||||
|
let delta_args = vec!["btm", "--time_delta", "2 min"];
|
||||||
|
let matches = app.get_matches_from(delta_args);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_time_interval(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(2 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let default_time_args = vec!["btm", "--default_time_value", "300s"];
|
||||||
|
let matches = app.get_matches_from(default_time_args);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_default_time_value(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(5 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn matches_number_times() {
|
||||||
|
let config = Config::default();
|
||||||
|
let app = crate::clap::build_app();
|
||||||
|
|
||||||
|
{
|
||||||
|
let app = app.clone();
|
||||||
|
let delta_args = vec!["btm", "--time_delta", "120000"];
|
||||||
|
let matches = app.get_matches_from(delta_args);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_time_interval(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(2 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let default_time_args = vec!["btm", "--default_time_value", "300000"];
|
||||||
|
let matches = app.get_matches_from(default_time_args);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_default_time_value(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(5 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn config_human_times() {
|
||||||
|
let app = crate::clap::build_app();
|
||||||
|
let matches = app.get_matches_from(["btm"]);
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
let flags = ConfigFlags {
|
||||||
|
time_delta: Some("2 min".to_string()),
|
||||||
|
default_time_value: Some("300s".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
config.flags = Some(flags);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_time_interval(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(2 * 60 * 1000)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_default_time_value(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(5 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn config_number_times() {
|
||||||
|
let app = crate::clap::build_app();
|
||||||
|
let matches = app.get_matches_from(["btm"]);
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
let flags = ConfigFlags {
|
||||||
|
time_delta: Some("120000".to_string()),
|
||||||
|
default_time_value: Some("300000".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
config.flags = Some(flags);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_time_interval(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(2 * 60 * 1000)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_default_time_value(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(5 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn create_app(mut config: Config, matches: ArgMatches) -> App {
|
fn create_app(mut config: Config, matches: ArgMatches) -> App {
|
||||||
let (layout, id, ty) = get_widget_layout(&matches, &config).unwrap();
|
let (layout, id, ty) = get_widget_layout(&matches, &config).unwrap();
|
||||||
|
|
Loading…
Reference in a new issue