feature: support human times for rate (#1221)

This commit is contained in:
Clement Tsang 2023-06-23 07:42:16 +00:00 committed by GitHub
parent 0b7f4c745d
commit cc3833289f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 53 deletions

View File

@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1216](https://github.com/ClementTsang/bottom/pull/1216): Fix arguments not being sorted alphabetically. - [#1216](https://github.com/ClementTsang/bottom/pull/1216): Fix arguments not being sorted alphabetically.
- [#1219](https://github.com/ClementTsang/bottom/pull/1219): Fix overflow/underflow in graph timespan zoom. - [#1219](https://github.com/ClementTsang/bottom/pull/1219): Fix overflow/underflow in graph timespan zoom.
## Features
- [#1221](https://github.com/ClementTsang/bottom/pull/1221): Support human times for `rate`.
## [0.9.2] - 2023-06-11 ## [0.9.2] - 2023-06-11
## Bug Fixes ## Bug Fixes

View File

@ -45,7 +45,7 @@ pub enum AxisScaling {
/// by config files or launch options. /// by config files or launch options.
#[derive(Debug, Default, Eq, PartialEq)] #[derive(Debug, Default, Eq, PartialEq)]
pub struct AppConfigFields { pub struct AppConfigFields {
pub update_rate_in_milliseconds: u64, pub update_rate: u64,
pub temperature_type: temperature::TemperatureType, pub temperature_type: temperature::TemperatureType,
pub use_dot: bool, pub use_dot: bool,
pub left_legend: bool, pub left_legend: bool,

View File

@ -353,8 +353,8 @@ use CPU (3) as the default instead.
.long("rate") .long("rate")
.action(ArgAction::Set) .action(ArgAction::Set)
.value_name("MS") .value_name("MS")
.help("Sets a refresh rate in ms.") .help("Sets the data refresh rate.")
.long_help("Sets a refresh rate in milliseconds. The minimum is 250ms, and defaults to 1000ms. Smaller values may take more computer resources."); .long_help("Sets the data refresh rate. The minimum is 250ms, and defaults to 1000ms. Smaller values may take more computer resources.");
let time_delta = Arg::new("time_delta") let time_delta = Arg::new("time_delta")
.short('d') .short('d')

View File

@ -520,7 +520,7 @@ pub const CONFIG_TEXT: &str = r##"# This is a default config file for bottom. A
# Whether to use dot markers rather than braille. # Whether to use dot markers rather than braille.
#dot_marker = false #dot_marker = false
# The update rate of the application. # The update rate of the application.
#rate = 1000 #rate = "1s"
# Whether to put the CPU legend to the left. # Whether to put the CPU legend to the left.
#left_legend = false #left_legend = false
# Whether to set CPU% on a process to be based on the total CPU or just current usage. # Whether to set CPU% on a process to be based on the total CPU or just current usage.

View File

@ -484,7 +484,7 @@ pub fn create_collection_thread(
let use_current_cpu_total = app_config_fields.use_current_cpu_total; let use_current_cpu_total = app_config_fields.use_current_cpu_total;
let unnormalized_cpu = app_config_fields.unnormalized_cpu; let unnormalized_cpu = app_config_fields.unnormalized_cpu;
let show_average_cpu = app_config_fields.show_average_cpu; let show_average_cpu = app_config_fields.show_average_cpu;
let update_time = app_config_fields.update_rate_in_milliseconds; let update_time = app_config_fields.update_rate;
thread::spawn(move || { thread::spawn(move || {
let mut data_state = data_harvester::DataCollector::new(filters); let mut data_state = data_harvester::DataCollector::new(filters);

View File

@ -66,45 +66,45 @@ impl From<u64> for StringOrNum {
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct ConfigFlags { pub struct ConfigFlags {
pub hide_avg_cpu: Option<bool>, hide_avg_cpu: Option<bool>,
pub dot_marker: Option<bool>, dot_marker: Option<bool>,
pub temperature_type: Option<String>, temperature_type: Option<String>,
pub rate: Option<u64>, rate: Option<StringOrNum>,
pub left_legend: Option<bool>, left_legend: Option<bool>,
pub current_usage: Option<bool>, current_usage: Option<bool>,
pub unnormalized_cpu: Option<bool>, unnormalized_cpu: Option<bool>,
pub group_processes: Option<bool>, group_processes: Option<bool>,
pub case_sensitive: Option<bool>, case_sensitive: Option<bool>,
pub whole_word: Option<bool>, whole_word: Option<bool>,
pub regex: Option<bool>, regex: Option<bool>,
pub basic: Option<bool>, basic: Option<bool>,
default_time_value: Option<StringOrNum>, default_time_value: Option<StringOrNum>,
time_delta: Option<StringOrNum>, time_delta: Option<StringOrNum>,
pub autohide_time: Option<bool>, autohide_time: Option<bool>,
pub hide_time: Option<bool>, hide_time: Option<bool>,
pub default_widget_type: Option<String>, default_widget_type: Option<String>,
pub default_widget_count: Option<u64>, default_widget_count: Option<u64>,
pub expanded_on_startup: Option<bool>, expanded_on_startup: Option<bool>,
pub use_old_network_legend: Option<bool>, use_old_network_legend: Option<bool>,
pub hide_table_gap: Option<bool>, hide_table_gap: Option<bool>,
pub battery: Option<bool>, battery: Option<bool>,
pub disable_click: Option<bool>, disable_click: Option<bool>,
pub no_write: Option<bool>, no_write: Option<bool>,
/// For built-in colour palettes. /// For built-in colour palettes.
pub color: Option<String>, color: Option<String>,
pub mem_as_value: Option<bool>, mem_as_value: Option<bool>,
pub tree: Option<bool>, tree: Option<bool>,
show_table_scroll_position: Option<bool>, show_table_scroll_position: Option<bool>,
pub process_command: Option<bool>, process_command: Option<bool>,
pub disable_advanced_kill: Option<bool>, disable_advanced_kill: Option<bool>,
pub network_use_bytes: Option<bool>, network_use_bytes: Option<bool>,
pub network_use_log: Option<bool>, network_use_log: Option<bool>,
pub network_use_binary_prefix: Option<bool>, network_use_binary_prefix: Option<bool>,
pub enable_gpu_memory: Option<bool>, enable_gpu_memory: Option<bool>,
pub enable_cache_memory: Option<bool>, enable_cache_memory: Option<bool>,
#[serde(with = "humantime_serde")] #[serde(with = "humantime_serde")]
#[serde(default)] #[serde(default)]
pub retention: Option<Duration>, retention: Option<Duration>,
} }
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
@ -262,7 +262,7 @@ pub fn build_app(
}; };
let app_config_fields = AppConfigFields { let app_config_fields = AppConfigFields {
update_rate_in_milliseconds: get_update_rate_in_milliseconds(matches, config) update_rate: get_update_rate(matches, config)
.context("Update 'rate' in your config file.")?, .context("Update 'rate' in your config file.")?,
temperature_type: get_temperature(matches, config) temperature_type: get_temperature(matches, config)
.context("Update 'temperature_type' in your config file.")?, .context("Update 'temperature_type' in your config file.")?,
@ -549,16 +549,15 @@ pub fn get_widget_layout(
Ok((bottom_layout, default_widget_id, default_widget_type)) Ok((bottom_layout, default_widget_id, default_widget_type))
} }
fn get_update_rate_in_milliseconds(matches: &ArgMatches, config: &Config) -> error::Result<u64> { fn get_update_rate(matches: &ArgMatches, config: &Config) -> error::Result<u64> {
let update_rate_in_milliseconds = if let Some(update_rate) = matches.get_one::<String>("rate") { let update_rate = if let Some(update_rate) = matches.get_one::<String>("rate") {
update_rate.parse::<u64>().map_err(|_| { try_parse_ms(update_rate)?
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(rate) = flags.rate { if let Some(rate) = &flags.rate {
rate match rate {
StringOrNum::String(s) => try_parse_ms(s)?,
StringOrNum::Num(n) => *n,
}
} else { } else {
DEFAULT_REFRESH_RATE_IN_MILLISECONDS DEFAULT_REFRESH_RATE_IN_MILLISECONDS
} }
@ -566,13 +565,13 @@ fn get_update_rate_in_milliseconds(matches: &ArgMatches, config: &Config) -> err
DEFAULT_REFRESH_RATE_IN_MILLISECONDS DEFAULT_REFRESH_RATE_IN_MILLISECONDS
}; };
if update_rate_in_milliseconds < 250 { if update_rate < 250 {
return Err(BottomError::ConfigError( return Err(BottomError::ConfigError(
"set your update rate to be at least 250 milliseconds.".to_string(), "set your update rate to be at least 250 ms.".to_string(),
)); ));
} }
Ok(update_rate_in_milliseconds) Ok(update_rate)
} }
fn get_temperature( fn get_temperature(
@ -914,7 +913,7 @@ mod test {
use crate::{ use crate::{
app::App, app::App,
canvas::canvas_styling::CanvasStyling, canvas::canvas_styling::CanvasStyling,
options::{get_default_time_value, try_parse_ms, ConfigFlags}, options::{get_default_time_value, get_update_rate, try_parse_ms, ConfigFlags},
}; };
#[test] #[test]
@ -999,6 +998,7 @@ mod test {
let flags = ConfigFlags { let flags = ConfigFlags {
time_delta: Some("2 min".to_string().into()), time_delta: Some("2 min".to_string().into()),
default_time_value: Some("300s".to_string().into()), default_time_value: Some("300s".to_string().into()),
rate: Some("1s".to_string().into()),
..Default::default() ..Default::default()
}; };
@ -1013,6 +1013,8 @@ mod test {
get_default_time_value(&matches, &config, 60 * 60 * 1000), get_default_time_value(&matches, &config, 60 * 60 * 1000),
Ok(5 * 60 * 1000) Ok(5 * 60 * 1000)
); );
assert_eq!(get_update_rate(&matches, &config), Ok(1000));
} }
#[test] #[test]
@ -1024,6 +1026,7 @@ mod test {
let flags = ConfigFlags { let flags = ConfigFlags {
time_delta: Some("120000".to_string().into()), time_delta: Some("120000".to_string().into()),
default_time_value: Some("300000".to_string().into()), default_time_value: Some("300000".to_string().into()),
rate: Some("1000".to_string().into()),
..Default::default() ..Default::default()
}; };
@ -1038,6 +1041,8 @@ mod test {
get_default_time_value(&matches, &config, 60 * 60 * 1000), get_default_time_value(&matches, &config, 60 * 60 * 1000),
Ok(5 * 60 * 1000) Ok(5 * 60 * 1000)
); );
assert_eq!(get_update_rate(&matches, &config), Ok(1000));
} }
#[test] #[test]
@ -1049,6 +1054,7 @@ mod test {
let flags = ConfigFlags { let flags = ConfigFlags {
time_delta: Some(120000.into()), time_delta: Some(120000.into()),
default_time_value: Some(300000.into()), default_time_value: Some(300000.into()),
rate: Some(1000.into()),
..Default::default() ..Default::default()
}; };
@ -1063,6 +1069,8 @@ mod test {
get_default_time_value(&matches, &config, 60 * 60 * 1000), get_default_time_value(&matches, &config, 60 * 60 * 1000),
Ok(5 * 60 * 1000) Ok(5 * 60 * 1000)
); );
assert_eq!(get_update_rate(&matches, &config), Ok(1000));
} }
fn create_app(config: Config, matches: ArgMatches) -> App { fn create_app(config: Config, matches: ArgMatches) -> App {

View File

@ -15,7 +15,7 @@ fn test_small_rate() {
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your update rate to be at least 250 milliseconds.", "set your update rate to be at least 250 ms.",
)); ));
} }