From a7973df6021eeefa586ad0374101822d4770cc89 Mon Sep 17 00:00:00 2001 From: Regolith Linux Date: Sat, 10 Feb 2024 10:13:53 -0800 Subject: [PATCH 1/3] feat: allow configuration to be read from stdin if the config file path string is '-' --- src/main.rs | 28 +++++++++++++++++++++++++--- src/util.rs | 14 +++++++++++++- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index c9ea3489..5bec46c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::io::Read; + use clap::Parser; use i3status_rs::config::Config; @@ -6,6 +8,8 @@ use i3status_rs::escape::Escaped; use i3status_rs::widget::{State, Widget}; use i3status_rs::{protocol, util, BarState}; +const STDIN_FILE_DESIGNATOR: &str = "-"; + fn main() { env_logger::init(); @@ -22,9 +26,27 @@ fn main() { .build() .unwrap() .block_on(async move { - let config_path = util::find_file(&args.config, None, Some("toml")) - .or_error(|| format!("Configuration file '{}' not found", args.config))?; - let mut config: Config = util::deserialize_toml_file(&config_path)?; + let mut config: Config = match args.config.as_str() { + STDIN_FILE_DESIGNATOR => { // read from stdin + let mut config_str = String::new(); + + let size = std::io::stdin().read_to_string(&mut config_str) + .or_error(|| format!("Configuration file could not be read from stdin"))?; + + if size == 0 { + return Err(i3status_rs::errors::Error { kind: ErrorKind::Config, message: None, cause: None, block: None }); + } + + util::deserialize_toml(&config_str, None)? + }, + _ => { // read from file path + let config_path = util::find_file(&args.config, None, Some("toml")) + .or_error(|| format!("Configuration file '{}' not found", args.config))?; + let config_str = util::read_file(&config_path).await.or_error(|| format!("Configuration file '{}' not found", args.config))?; + util::deserialize_toml(&config_str, Some(&config_path))? + } + }; + let blocks = std::mem::take(&mut config.blocks); let mut bar = BarState::new(config); for block_config in blocks { diff --git a/src/util.rs b/src/util.rs index 6b5eb420..d4ce95f3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -95,6 +95,18 @@ where let contents = std::fs::read_to_string(path) .or_error(|| format!("Failed to read file: {}", path.display()))?; + self::deserialize_toml(&contents, Some(&path)) +} + +pub fn deserialize_toml(contents: &String, file_path: Option<&Path>) -> Result +where + T: DeserializeOwned, +{ + let source = match file_path { + Some(msg) => msg.display().to_string(), + _ => String::from("(from stdin)") + }; + toml::from_str(&contents).map_err(|err| { #[allow(deprecated)] let location_msg = err @@ -109,7 +121,7 @@ where .unwrap_or_default(); Error::new(format!( "Failed to deserialize TOML file {}{}: {}", - path.display(), + source, location_msg, err.message() )) From 76b0249986cbc0c25a8894fd741bbd34d3907cbe Mon Sep 17 00:00:00 2001 From: Regolith Linux Date: Sat, 10 Feb 2024 10:42:58 -0800 Subject: [PATCH 2/3] chore: cleanup --- src/main.rs | 32 ++++++++++++++++++++++---------- src/util.rs | 6 +++--- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5bec46c3..b3e22ba2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,22 +27,34 @@ fn main() { .unwrap() .block_on(async move { let mut config: Config = match args.config.as_str() { - STDIN_FILE_DESIGNATOR => { // read from stdin + STDIN_FILE_DESIGNATOR => { + // read from stdin let mut config_str = String::new(); - let size = std::io::stdin().read_to_string(&mut config_str) - .or_error(|| format!("Configuration file could not be read from stdin"))?; - - if size == 0 { - return Err(i3status_rs::errors::Error { kind: ErrorKind::Config, message: None, cause: None, block: None }); + let size = std::io::stdin() + .read_to_string(&mut config_str) + .or_error(|| { + "Configuration file could not be read from stdin".to_string() + })?; + + if size == 0 { + return Err(i3status_rs::errors::Error { + kind: ErrorKind::Config, + message: None, + cause: None, + block: None, + }); } util::deserialize_toml(&config_str, None)? - }, - _ => { // read from file path + } + _ => { + // read from file path let config_path = util::find_file(&args.config, None, Some("toml")) - .or_error(|| format!("Configuration file '{}' not found", args.config))?; - let config_str = util::read_file(&config_path).await.or_error(|| format!("Configuration file '{}' not found", args.config))?; + .or_error(|| format!("Configuration file '{}' not found", args.config))?; + let config_str = util::read_file(&config_path) + .await + .or_error(|| format!("Configuration file '{}' not found", args.config))?; util::deserialize_toml(&config_str, Some(&config_path))? } }; diff --git a/src/util.rs b/src/util.rs index d4ce95f3..a3615155 100644 --- a/src/util.rs +++ b/src/util.rs @@ -95,7 +95,7 @@ where let contents = std::fs::read_to_string(path) .or_error(|| format!("Failed to read file: {}", path.display()))?; - self::deserialize_toml(&contents, Some(&path)) + self::deserialize_toml(&contents, Some(path)) } pub fn deserialize_toml(contents: &String, file_path: Option<&Path>) -> Result @@ -104,10 +104,10 @@ where { let source = match file_path { Some(msg) => msg.display().to_string(), - _ => String::from("(from stdin)") + _ => String::from("(from stdin)"), }; - toml::from_str(&contents).map_err(|err| { + toml::from_str(contents).map_err(|err| { #[allow(deprecated)] let location_msg = err .span() From c36ce615653fe9a2c22f0af083052881d9f3689e Mon Sep 17 00:00:00 2001 From: Regolith Linux Date: Sat, 10 Feb 2024 18:10:36 -0800 Subject: [PATCH 3/3] fix: try tokio stdin to see if resolves crash --- src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index b3e22ba2..22adb842 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use i3status_rs::errors::*; use i3status_rs::escape::Escaped; use i3status_rs::widget::{State, Widget}; use i3status_rs::{protocol, util, BarState}; +use tokio::io::{stdin, AsyncReadExt}; const STDIN_FILE_DESIGNATOR: &str = "-"; @@ -31,8 +32,9 @@ fn main() { // read from stdin let mut config_str = String::new(); - let size = std::io::stdin() + let size = stdin() .read_to_string(&mut config_str) + .await .or_error(|| { "Configuration file could not be read from stdin".to_string() })?;