From 6f3c6ec8408a34548993870202067d0229cc5800 Mon Sep 17 00:00:00 2001 From: tangowithfoxtrot <5676771+tangowithfoxtrot@users.noreply.github.com> Date: Sun, 26 Jan 2025 09:28:47 -0800 Subject: [PATCH 1/6] feat: var interpolation --- src/app/mod.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/app/mod.rs b/src/app/mod.rs index eec1ed7..41aa3e5 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -213,6 +213,71 @@ pub struct Data<'a> { pub sonarr_data: SonarrData<'a>, } +fn deserialize_env_var<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let s: String = String::deserialize(deserializer)?; + let interpolated = interpolate_env_vars(&s); + Ok(interpolated) +} + +fn deserialize_optional_env_var<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let s: Option = Option::deserialize(deserializer)?; + match s { + Some(value) => { + let interpolated = interpolate_env_vars(&value); + Ok(Some(interpolated)) + } + None => Ok(None), + } +} + +fn deserialize_u16_env_var<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let s: Option = Option::deserialize(deserializer)?; + match s { + Some(value) => { + let interpolated = interpolate_env_vars(&value); + interpolated + .parse::() + .map(Some) + .map_err(serde::de::Error::custom) + } + None => Ok(None), + } +} + +fn interpolate_env_vars(s: &str) -> String { + let mut result = s.to_string(); + let start = "${"; + let end = "}"; + + while let Some(start_index) = result.find(start) { + let end_index = result[start_index..] + .find(end) + .map(|i| start_index + i + end.len()); + if let Some(end_index) = end_index { + let var_name = &result[start_index + start.len()..end_index - end.len()]; + if let Ok(value) = std::env::var(var_name) { + // Match found; interpolate + result.replace_range(start_index..end_index, &value); + } else { + break; // No var match found; interpret it literally + } + } else { + break; // No closing brace found + } + } + + result +} + #[derive(Debug, Deserialize, Serialize, Default, Clone)] pub struct AppConfig { pub radarr: Option, @@ -260,10 +325,15 @@ impl AppConfig { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct ServarrConfig { + #[serde(deserialize_with = "deserialize_optional_env_var")] pub host: Option, + #[serde(deserialize_with = "deserialize_u16_env_var")] pub port: Option, + #[serde(deserialize_with = "deserialize_optional_env_var")] pub uri: Option, + #[serde(deserialize_with = "deserialize_env_var")] pub api_token: String, + #[serde(deserialize_with = "deserialize_optional_env_var")] pub ssl_cert_path: Option, } From c4ace8c53fd6377dc042d171bfa40e1c5a3b069c Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Sun, 26 Jan 2025 14:59:09 -0700 Subject: [PATCH 2/6] feat: Tweaked the implementation for environment variables in the config a bit --- src/app/app_tests.rs | 66 ++++++++++++++++++++- src/app/mod.rs | 134 +++++++++++++++++++++---------------------- 2 files changed, 128 insertions(+), 72 deletions(-) diff --git a/src/app/app_tests.rs b/src/app/app_tests.rs index 59cfb8e..e7a5084 100644 --- a/src/app/app_tests.rs +++ b/src/app/app_tests.rs @@ -2,12 +2,16 @@ mod tests { use crate::models::Route; use anyhow::anyhow; - use pretty_assertions::assert_eq; + use pretty_assertions::{assert_eq, assert_str_eq}; use rstest::rstest; + use serde::de::value::StringDeserializer; + use serde::de::IntoDeserializer; use tokio::sync::mpsc; use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES}; - use crate::app::{App, AppConfig, Data, ServarrConfig}; + use crate::app::{ + deserialize_env_var, interpolate_env_vars, App, AppConfig, Data, ServarrConfig, + }; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData}; use crate::models::{HorizontallyScrollableText, TabRoute}; @@ -347,4 +351,62 @@ mod tests { assert!(servarr_config.api_token.is_empty()); assert_eq!(servarr_config.ssl_cert_path, None); } + + #[test] + fn test_deserialize_env_var() { + std::env::set_var("TEST_VAR_DESERIALIZE", "testing"); + let deserializer: StringDeserializer = + "${TEST_VAR_DESERIALIZE}".to_owned().into_deserializer(); + + let env_var: Result = deserialize_env_var(deserializer); + + assert!(env_var.is_ok()); + assert_str_eq!(env_var.unwrap(), "testing"); + std::env::remove_var("TEST_VAR_DESERIALIZE"); + } + + #[test] + fn test_interpolate_env_vars() { + std::env::set_var("TEST_VAR_INTERPOLATION", "testing"); + + let var = interpolate_env_vars("${TEST_VAR_INTERPOLATION}"); + + assert_str_eq!(var, "testing"); + std::env::remove_var("TEST_VAR_INTERPOLATION"); + } + + #[test] + fn test_interpolate_env_vars_defaults_to_original_string_if_not_in_yaml_interpolation_format() { + let var = interpolate_env_vars("TEST_VAR_INTERPOLATION"); + + assert_str_eq!(var, "TEST_VAR_INTERPOLATION"); + } + + #[test] + fn test_interpolate_env_vars_scrubs_all_unnecessary_characters() { + std::env::set_var( + "TEST_VAR_INTERPOLATION_UNNECESSARY_CHARACTERS", + r#""" + `"'https://dontdo:this@testing.com/query?test=%20query#results'"` {([\|$!])} + """#, + ); + + let var = interpolate_env_vars("${TEST_VAR_INTERPOLATION_UNNECESSARY_CHARACTERS}"); + + assert_str_eq!( + var, + "https://dontdo:this@testing.com/query?test=%20query#results" + ); + std::env::remove_var("TEST_VAR_INTERPOLATION_UNNECESSARY_CHARACTERS"); + } + + #[test] + fn test_interpolate_env_vars_scrubs_all_unnecessary_characters_from_non_environment_variable() { + let var = interpolate_env_vars("https://dontdo:this@testing.com/query?test=%20query#results"); + + assert_str_eq!( + var, + "https://dontdo:this@testing.com/query?test=%20query#results" + ); + } } diff --git a/src/app/mod.rs b/src/app/mod.rs index 41aa3e5..760bc7e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -3,6 +3,7 @@ use std::process; use anyhow::{anyhow, Error}; use colored::Colorize; use log::{debug, error}; +use regex::Regex; use serde::{Deserialize, Serialize}; use tokio::sync::mpsc::Sender; use tokio_util::sync::CancellationToken; @@ -213,71 +214,6 @@ pub struct Data<'a> { pub sonarr_data: SonarrData<'a>, } -fn deserialize_env_var<'de, D>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, -{ - let s: String = String::deserialize(deserializer)?; - let interpolated = interpolate_env_vars(&s); - Ok(interpolated) -} - -fn deserialize_optional_env_var<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - let s: Option = Option::deserialize(deserializer)?; - match s { - Some(value) => { - let interpolated = interpolate_env_vars(&value); - Ok(Some(interpolated)) - } - None => Ok(None), - } -} - -fn deserialize_u16_env_var<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - let s: Option = Option::deserialize(deserializer)?; - match s { - Some(value) => { - let interpolated = interpolate_env_vars(&value); - interpolated - .parse::() - .map(Some) - .map_err(serde::de::Error::custom) - } - None => Ok(None), - } -} - -fn interpolate_env_vars(s: &str) -> String { - let mut result = s.to_string(); - let start = "${"; - let end = "}"; - - while let Some(start_index) = result.find(start) { - let end_index = result[start_index..] - .find(end) - .map(|i| start_index + i + end.len()); - if let Some(end_index) = end_index { - let var_name = &result[start_index + start.len()..end_index - end.len()]; - if let Ok(value) = std::env::var(var_name) { - // Match found; interpolate - result.replace_range(start_index..end_index, &value); - } else { - break; // No var match found; interpret it literally - } - } else { - break; // No closing brace found - } - } - - result -} - #[derive(Debug, Deserialize, Serialize, Default, Clone)] pub struct AppConfig { pub radarr: Option, @@ -325,15 +261,15 @@ impl AppConfig { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct ServarrConfig { - #[serde(deserialize_with = "deserialize_optional_env_var")] + #[serde(default, deserialize_with = "deserialize_optional_env_var")] pub host: Option, - #[serde(deserialize_with = "deserialize_u16_env_var")] + #[serde(default, deserialize_with = "deserialize_u16_env_var")] pub port: Option, - #[serde(deserialize_with = "deserialize_optional_env_var")] + #[serde(default, deserialize_with = "deserialize_optional_env_var")] pub uri: Option, - #[serde(deserialize_with = "deserialize_env_var")] + #[serde(default, deserialize_with = "deserialize_env_var")] pub api_token: String, - #[serde(deserialize_with = "deserialize_optional_env_var")] + #[serde(default, deserialize_with = "deserialize_optional_env_var")] pub ssl_cert_path: Option, } @@ -362,3 +298,61 @@ pub fn log_and_print_error(error: String) { error!("{}", error); eprintln!("error: {}", error.red()); } + +fn deserialize_env_var<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let s: String = String::deserialize(deserializer)?; + let interpolated = interpolate_env_vars(&s); + Ok(interpolated) +} + +fn deserialize_optional_env_var<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let s: Option = Option::deserialize(deserializer)?; + match s { + Some(value) => { + let interpolated = interpolate_env_vars(&value); + Ok(Some(interpolated)) + } + None => Ok(None), + } +} + +fn deserialize_u16_env_var<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let s: Option = Option::deserialize(deserializer)?; + match s { + Some(value) => { + let interpolated = interpolate_env_vars(&value); + interpolated + .parse::() + .map(Some) + .map_err(serde::de::Error::custom) + } + None => Ok(None), + } +} + +fn interpolate_env_vars(s: &str) -> String { + let result = s.to_string(); + let scrubbing_regex = Regex::new(r#"[\s\{\}!\$^\(\)\[\]\\\|`'"]+"#).unwrap(); + let var_regex = Regex::new(r"\$\{(.*?)\}").unwrap(); + + var_regex + .replace_all(s, |caps: ®ex::Captures<'_>| { + if let Some(mat) = caps.get(1) { + if let Ok(value) = std::env::var(mat.as_str()) { + return scrubbing_regex.replace_all(&value, "").to_string(); + } + } + + scrubbing_regex.replace_all(&result, "").to_string() + }) + .to_string() +} From 8d450dea5ad01a9eb220d81f8323d21f9fd0f1c0 Mon Sep 17 00:00:00 2001 From: tangowithfoxtrot <5676771+tangowithfoxtrot@users.noreply.github.com> Date: Sun, 26 Jan 2025 14:36:45 -0800 Subject: [PATCH 3/6] Merge branch 'main' into var-interpolation --- Cargo.lock | 22 +++++++++++++++++++ Cargo.toml | 1 + src/app/app_tests.rs | 19 ++++++++++++++++ src/app/mod.rs | 8 ++++--- src/app/radarr/mod.rs | 2 +- src/app/sonarr/mod.rs | 2 +- src/handlers/radarr_handlers/blocklist/mod.rs | 2 +- .../collections/collection_details_handler.rs | 2 +- .../collections/edit_collection_handler.rs | 2 +- .../radarr_handlers/collections/mod.rs | 2 +- src/handlers/radarr_handlers/downloads/mod.rs | 2 +- .../indexers/edit_indexer_handler.rs | 2 +- .../indexers/edit_indexer_settings_handler.rs | 2 +- src/handlers/radarr_handlers/indexers/mod.rs | 2 +- .../indexers/test_all_indexers_handler.rs | 2 +- .../library/add_movie_handler.rs | 2 +- .../library/delete_movie_handler.rs | 2 +- .../library/edit_movie_handler.rs | 2 +- src/handlers/radarr_handlers/library/mod.rs | 2 +- .../library/movie_details_handler.rs | 2 +- .../radarr_handlers/root_folders/mod.rs | 2 +- .../system/system_details_handler.rs | 2 +- src/handlers/sonarr_handlers/blocklist/mod.rs | 2 +- src/handlers/sonarr_handlers/downloads/mod.rs | 2 +- src/handlers/sonarr_handlers/history/mod.rs | 2 +- .../indexers/edit_indexer_handler.rs | 2 +- .../indexers/edit_indexer_settings_handler.rs | 2 +- src/handlers/sonarr_handlers/indexers/mod.rs | 2 +- .../indexers/test_all_indexers_handler.rs | 2 +- .../library/add_series_handler.rs | 2 +- .../library/delete_series_handler.rs | 2 +- .../library/edit_series_handler.rs | 2 +- .../library/episode_details_handler.rs | 2 +- src/handlers/sonarr_handlers/library/mod.rs | 2 +- .../library/season_details_handler.rs | 2 +- .../library/series_details_handler.rs | 2 +- .../sonarr_handlers/root_folders/mod.rs | 2 +- .../system/system_details_handler.rs | 2 +- src/handlers/table_handler_tests.rs | 2 +- src/main.rs | 5 +++-- src/models/mod.rs | 2 +- src/models/servarr_data/radarr/radarr_data.rs | 2 +- src/models/servarr_data/sonarr/sonarr_data.rs | 2 +- src/network/mod.rs | 2 +- src/network/radarr_network.rs | 2 +- src/network/sonarr_network.rs | 2 +- src/ui/styles.rs | 2 +- src/ui/widgets/button.rs | 4 ++-- src/ui/widgets/checkbox.rs | 2 +- src/ui/widgets/confirmation_prompt.rs | 4 ++-- src/ui/widgets/input_box.rs | 4 ++-- src/ui/widgets/input_box_popup.rs | 2 +- src/ui/widgets/loading_block.rs | 2 +- src/ui/widgets/message.rs | 2 +- src/ui/widgets/popup.rs | 2 +- 55 files changed, 103 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6aab89..db2924e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1359,6 +1359,7 @@ dependencies = [ "tokio", "tokio-util", "urlencoding", + "veil", ] [[package]] @@ -2644,6 +2645,27 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "veil" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f00796f9c5969da55497f5c8802c2e69eaf21c0166fe28b6006c7c4699f4d0e" +dependencies = [ + "once_cell", + "veil-macros", +] + +[[package]] +name = "veil-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b2d5567b6fbd34e8f0488d56b648e67c0d999535f4af2060d14f9074b43e833" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 23798eb..a6e60d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ derive_setters = "0.1.6" deunicode = "1.6.0" paste = "1.0.15" openssl = { version = "0.10.68", features = ["vendored"] } +veil = "0.2.0" [dev-dependencies] assert_cmd = "2.0.16" diff --git a/src/app/app_tests.rs b/src/app/app_tests.rs index e7a5084..857fa46 100644 --- a/src/app/app_tests.rs +++ b/src/app/app_tests.rs @@ -409,4 +409,23 @@ mod tests { "https://dontdo:this@testing.com/query?test=%20query#results" ); } + + fn test_servarr_config_redacted_debug() { + let host = "localhost".to_owned(); + let port = 1234; + let uri = "http://localhost:1234".to_owned(); + let api_token = "thisisatest".to_owned(); + let ssl_cert_path = "/some/path".to_owned(); + let expected_str = format!("ServarrConfig {{ host: Some(\"{}\"), port: Some({}), uri: Some(\"{}\"), api_token: \"***********\", ssl_cert_path: Some(\"{}\") }}", + host, port, uri, ssl_cert_path); + let servarr_config = ServarrConfig { + host: Some(host), + port: Some(port), + uri: Some(uri), + api_token, + ssl_cert_path: Some(ssl_cert_path), + }; + + assert_str_eq!(format!("{servarr_config:?}"), expected_str); + } } diff --git a/src/app/mod.rs b/src/app/mod.rs index 760bc7e..744b5be 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -7,6 +7,7 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use tokio::sync::mpsc::Sender; use tokio_util::sync::CancellationToken; +use veil::Redact; use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES}; use crate::cli::Command; @@ -43,7 +44,7 @@ pub struct App<'a> { pub data: Data<'a>, } -impl<'a> App<'a> { +impl App<'_> { pub fn new( network_tx: Sender, config: AppConfig, @@ -166,7 +167,7 @@ impl<'a> App<'a> { } } -impl<'a> Default for App<'a> { +impl Default for App<'_> { fn default() -> Self { App { navigation_stack: Vec::new(), @@ -259,7 +260,7 @@ impl AppConfig { } } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Redact, Deserialize, Serialize, Clone)] pub struct ServarrConfig { #[serde(default, deserialize_with = "deserialize_optional_env_var")] pub host: Option, @@ -268,6 +269,7 @@ pub struct ServarrConfig { #[serde(default, deserialize_with = "deserialize_optional_env_var")] pub uri: Option, #[serde(default, deserialize_with = "deserialize_env_var")] + #[redact] pub api_token: String, #[serde(default, deserialize_with = "deserialize_optional_env_var")] pub ssl_cert_path: Option, diff --git a/src/app/radarr/mod.rs b/src/app/radarr/mod.rs index f1dcdd2..6ecba83 100644 --- a/src/app/radarr/mod.rs +++ b/src/app/radarr/mod.rs @@ -8,7 +8,7 @@ pub mod radarr_context_clues; #[path = "radarr_tests.rs"] mod radarr_tests; -impl<'a> App<'a> { +impl App<'_> { pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: &ActiveRadarrBlock) { match active_radarr_block { ActiveRadarrBlock::Blocklist => { diff --git a/src/app/sonarr/mod.rs b/src/app/sonarr/mod.rs index 62dd5f6..a0fc76a 100644 --- a/src/app/sonarr/mod.rs +++ b/src/app/sonarr/mod.rs @@ -11,7 +11,7 @@ pub mod sonarr_context_clues; #[path = "sonarr_tests.rs"] mod sonarr_tests; -impl<'a> App<'a> { +impl App<'_> { pub(super) async fn dispatch_by_sonarr_block(&mut self, active_sonarr_block: &ActiveSonarrBlock) { match active_sonarr_block { ActiveSonarrBlock::Series => { diff --git a/src/handlers/radarr_handlers/blocklist/mod.rs b/src/handlers/radarr_handlers/blocklist/mod.rs index 677b4c1..9dee67a 100644 --- a/src/handlers/radarr_handlers/blocklist/mod.rs +++ b/src/handlers/radarr_handlers/blocklist/mod.rs @@ -21,7 +21,7 @@ pub(super) struct BlocklistHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> BlocklistHandler<'a, 'b> { +impl BlocklistHandler<'_, '_> { handle_table_events!( self, blocklist, diff --git a/src/handlers/radarr_handlers/collections/collection_details_handler.rs b/src/handlers/radarr_handlers/collections/collection_details_handler.rs index dbc1f95..4780ee6 100644 --- a/src/handlers/radarr_handlers/collections/collection_details_handler.rs +++ b/src/handlers/radarr_handlers/collections/collection_details_handler.rs @@ -23,7 +23,7 @@ pub(super) struct CollectionDetailsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> CollectionDetailsHandler<'a, 'b> { +impl CollectionDetailsHandler<'_, '_> { handle_table_events!( self, collection_movies, diff --git a/src/handlers/radarr_handlers/collections/edit_collection_handler.rs b/src/handlers/radarr_handlers/collections/edit_collection_handler.rs index fbc59c0..04e3555 100644 --- a/src/handlers/radarr_handlers/collections/edit_collection_handler.rs +++ b/src/handlers/radarr_handlers/collections/edit_collection_handler.rs @@ -20,7 +20,7 @@ pub(super) struct EditCollectionHandler<'a, 'b> { context: Option, } -impl<'a, 'b> EditCollectionHandler<'a, 'b> { +impl EditCollectionHandler<'_, '_> { fn build_edit_collection_params(&mut self) -> EditCollectionParams { let edit_collection_modal = self .app diff --git a/src/handlers/radarr_handlers/collections/mod.rs b/src/handlers/radarr_handlers/collections/mod.rs index 498bee5..507a9f0 100644 --- a/src/handlers/radarr_handlers/collections/mod.rs +++ b/src/handlers/radarr_handlers/collections/mod.rs @@ -29,7 +29,7 @@ pub(super) struct CollectionsHandler<'a, 'b> { context: Option, } -impl<'a, 'b> CollectionsHandler<'a, 'b> { +impl CollectionsHandler<'_, '_> { handle_table_events!( self, collections, diff --git a/src/handlers/radarr_handlers/downloads/mod.rs b/src/handlers/radarr_handlers/downloads/mod.rs index daa2480..b4094d8 100644 --- a/src/handlers/radarr_handlers/downloads/mod.rs +++ b/src/handlers/radarr_handlers/downloads/mod.rs @@ -20,7 +20,7 @@ pub(super) struct DownloadsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> DownloadsHandler<'a, 'b> { +impl DownloadsHandler<'_, '_> { handle_table_events!( self, downloads, diff --git a/src/handlers/radarr_handlers/indexers/edit_indexer_handler.rs b/src/handlers/radarr_handlers/indexers/edit_indexer_handler.rs index cbbcee3..15350b1 100644 --- a/src/handlers/radarr_handlers/indexers/edit_indexer_handler.rs +++ b/src/handlers/radarr_handlers/indexers/edit_indexer_handler.rs @@ -19,7 +19,7 @@ pub(super) struct EditIndexerHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> EditIndexerHandler<'a, 'b> { +impl EditIndexerHandler<'_, '_> { fn build_edit_indexer_params(&mut self) -> EditIndexerParams { let edit_indexer_modal = self .app diff --git a/src/handlers/radarr_handlers/indexers/edit_indexer_settings_handler.rs b/src/handlers/radarr_handlers/indexers/edit_indexer_settings_handler.rs index f3d8bab..d304449 100644 --- a/src/handlers/radarr_handlers/indexers/edit_indexer_settings_handler.rs +++ b/src/handlers/radarr_handlers/indexers/edit_indexer_settings_handler.rs @@ -20,7 +20,7 @@ pub(super) struct IndexerSettingsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> IndexerSettingsHandler<'a, 'b> { +impl IndexerSettingsHandler<'_, '_> { fn build_edit_indexer_settings_body(&mut self) -> IndexerSettings { self .app diff --git a/src/handlers/radarr_handlers/indexers/mod.rs b/src/handlers/radarr_handlers/indexers/mod.rs index 15b7078..28371c9 100644 --- a/src/handlers/radarr_handlers/indexers/mod.rs +++ b/src/handlers/radarr_handlers/indexers/mod.rs @@ -31,7 +31,7 @@ pub(super) struct IndexersHandler<'a, 'b> { context: Option, } -impl<'a, 'b> IndexersHandler<'a, 'b> { +impl IndexersHandler<'_, '_> { handle_table_events!(self, indexers, self.app.data.radarr_data.indexers, Indexer); fn extract_indexer_id(&self) -> i64 { diff --git a/src/handlers/radarr_handlers/indexers/test_all_indexers_handler.rs b/src/handlers/radarr_handlers/indexers/test_all_indexers_handler.rs index 2aa96d8..220fa3f 100644 --- a/src/handlers/radarr_handlers/indexers/test_all_indexers_handler.rs +++ b/src/handlers/radarr_handlers/indexers/test_all_indexers_handler.rs @@ -17,7 +17,7 @@ pub(super) struct TestAllIndexersHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> TestAllIndexersHandler<'a, 'b> { +impl TestAllIndexersHandler<'_, '_> { handle_table_events!( self, indexer_test_all_results, diff --git a/src/handlers/radarr_handlers/library/add_movie_handler.rs b/src/handlers/radarr_handlers/library/add_movie_handler.rs index 51b2317..d0c90c0 100644 --- a/src/handlers/radarr_handlers/library/add_movie_handler.rs +++ b/src/handlers/radarr_handlers/library/add_movie_handler.rs @@ -24,7 +24,7 @@ pub(super) struct AddMovieHandler<'a, 'b> { context: Option, } -impl<'a, 'b> AddMovieHandler<'a, 'b> { +impl AddMovieHandler<'_, '_> { handle_table_events!( self, add_movie_search_results, diff --git a/src/handlers/radarr_handlers/library/delete_movie_handler.rs b/src/handlers/radarr_handlers/library/delete_movie_handler.rs index 4ac994c..4f8d320 100644 --- a/src/handlers/radarr_handlers/library/delete_movie_handler.rs +++ b/src/handlers/radarr_handlers/library/delete_movie_handler.rs @@ -17,7 +17,7 @@ pub(super) struct DeleteMovieHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> DeleteMovieHandler<'a, 'b> { +impl DeleteMovieHandler<'_, '_> { fn build_delete_movie_params(&mut self) -> DeleteMovieParams { let id = self.app.data.radarr_data.movies.current_selection().id; let delete_movie_files = self.app.data.radarr_data.delete_movie_files; diff --git a/src/handlers/radarr_handlers/library/edit_movie_handler.rs b/src/handlers/radarr_handlers/library/edit_movie_handler.rs index f351708..9201091 100644 --- a/src/handlers/radarr_handlers/library/edit_movie_handler.rs +++ b/src/handlers/radarr_handlers/library/edit_movie_handler.rs @@ -20,7 +20,7 @@ pub(super) struct EditMovieHandler<'a, 'b> { context: Option, } -impl<'a, 'b> EditMovieHandler<'a, 'b> { +impl EditMovieHandler<'_, '_> { fn build_edit_movie_params(&mut self) -> EditMovieParams { let movie_id = self.app.data.radarr_data.movies.current_selection().id; let edit_movie_modal = self diff --git a/src/handlers/radarr_handlers/library/mod.rs b/src/handlers/radarr_handlers/library/mod.rs index eafcf45..b7744a7 100644 --- a/src/handlers/radarr_handlers/library/mod.rs +++ b/src/handlers/radarr_handlers/library/mod.rs @@ -34,7 +34,7 @@ pub(super) struct LibraryHandler<'a, 'b> { context: Option, } -impl<'a, 'b> LibraryHandler<'a, 'b> { +impl LibraryHandler<'_, '_> { handle_table_events!(self, movies, self.app.data.radarr_data.movies, Movie); } diff --git a/src/handlers/radarr_handlers/library/movie_details_handler.rs b/src/handlers/radarr_handlers/library/movie_details_handler.rs index 8b740b4..2e41f47 100644 --- a/src/handlers/radarr_handlers/library/movie_details_handler.rs +++ b/src/handlers/radarr_handlers/library/movie_details_handler.rs @@ -28,7 +28,7 @@ pub(super) struct MovieDetailsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> MovieDetailsHandler<'a, 'b> { +impl MovieDetailsHandler<'_, '_> { handle_table_events!( self, movie_releases, diff --git a/src/handlers/radarr_handlers/root_folders/mod.rs b/src/handlers/radarr_handlers/root_folders/mod.rs index 98f6ccb..feb6879 100644 --- a/src/handlers/radarr_handlers/root_folders/mod.rs +++ b/src/handlers/radarr_handlers/root_folders/mod.rs @@ -21,7 +21,7 @@ pub(super) struct RootFoldersHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> RootFoldersHandler<'a, 'b> { +impl RootFoldersHandler<'_, '_> { handle_table_events!( self, root_folders, diff --git a/src/handlers/radarr_handlers/system/system_details_handler.rs b/src/handlers/radarr_handlers/system/system_details_handler.rs index 861f346..eaadb68 100644 --- a/src/handlers/radarr_handlers/system/system_details_handler.rs +++ b/src/handlers/radarr_handlers/system/system_details_handler.rs @@ -19,7 +19,7 @@ pub(super) struct SystemDetailsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> SystemDetailsHandler<'a, 'b> { +impl SystemDetailsHandler<'_, '_> { fn extract_task_name(&self) -> RadarrTaskName { self .app diff --git a/src/handlers/sonarr_handlers/blocklist/mod.rs b/src/handlers/sonarr_handlers/blocklist/mod.rs index 2b4e935..ce4d07d 100644 --- a/src/handlers/sonarr_handlers/blocklist/mod.rs +++ b/src/handlers/sonarr_handlers/blocklist/mod.rs @@ -21,7 +21,7 @@ pub(super) struct BlocklistHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> BlocklistHandler<'a, 'b> { +impl BlocklistHandler<'_, '_> { handle_table_events!( self, blocklist, diff --git a/src/handlers/sonarr_handlers/downloads/mod.rs b/src/handlers/sonarr_handlers/downloads/mod.rs index 00211bb..b7a3c46 100644 --- a/src/handlers/sonarr_handlers/downloads/mod.rs +++ b/src/handlers/sonarr_handlers/downloads/mod.rs @@ -20,7 +20,7 @@ pub(super) struct DownloadsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> DownloadsHandler<'a, 'b> { +impl DownloadsHandler<'_, '_> { handle_table_events!( self, downloads, diff --git a/src/handlers/sonarr_handlers/history/mod.rs b/src/handlers/sonarr_handlers/history/mod.rs index d0bd399..2a11ee7 100644 --- a/src/handlers/sonarr_handlers/history/mod.rs +++ b/src/handlers/sonarr_handlers/history/mod.rs @@ -21,7 +21,7 @@ pub(super) struct HistoryHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> HistoryHandler<'a, 'b> { +impl HistoryHandler<'_, '_> { handle_table_events!( self, history, diff --git a/src/handlers/sonarr_handlers/indexers/edit_indexer_handler.rs b/src/handlers/sonarr_handlers/indexers/edit_indexer_handler.rs index d5da277..485a4e2 100644 --- a/src/handlers/sonarr_handlers/indexers/edit_indexer_handler.rs +++ b/src/handlers/sonarr_handlers/indexers/edit_indexer_handler.rs @@ -19,7 +19,7 @@ pub(super) struct EditIndexerHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> EditIndexerHandler<'a, 'b> { +impl EditIndexerHandler<'_, '_> { fn build_edit_indexer_params(&mut self) -> EditIndexerParams { let edit_indexer_modal = self .app diff --git a/src/handlers/sonarr_handlers/indexers/edit_indexer_settings_handler.rs b/src/handlers/sonarr_handlers/indexers/edit_indexer_settings_handler.rs index 51a7441..4e1a45a 100644 --- a/src/handlers/sonarr_handlers/indexers/edit_indexer_settings_handler.rs +++ b/src/handlers/sonarr_handlers/indexers/edit_indexer_settings_handler.rs @@ -20,7 +20,7 @@ pub(super) struct IndexerSettingsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> IndexerSettingsHandler<'a, 'b> { +impl IndexerSettingsHandler<'_, '_> { fn build_edit_indexer_settings_params(&mut self) -> IndexerSettings { self .app diff --git a/src/handlers/sonarr_handlers/indexers/mod.rs b/src/handlers/sonarr_handlers/indexers/mod.rs index be21947..261ca3a 100644 --- a/src/handlers/sonarr_handlers/indexers/mod.rs +++ b/src/handlers/sonarr_handlers/indexers/mod.rs @@ -31,7 +31,7 @@ pub(super) struct IndexersHandler<'a, 'b> { context: Option, } -impl<'a, 'b> IndexersHandler<'a, 'b> { +impl IndexersHandler<'_, '_> { handle_table_events!(self, indexers, self.app.data.sonarr_data.indexers, Indexer); fn extract_indexer_id(&self) -> i64 { diff --git a/src/handlers/sonarr_handlers/indexers/test_all_indexers_handler.rs b/src/handlers/sonarr_handlers/indexers/test_all_indexers_handler.rs index 6db07fd..96de3ca 100644 --- a/src/handlers/sonarr_handlers/indexers/test_all_indexers_handler.rs +++ b/src/handlers/sonarr_handlers/indexers/test_all_indexers_handler.rs @@ -17,7 +17,7 @@ pub(super) struct TestAllIndexersHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> TestAllIndexersHandler<'a, 'b> { +impl TestAllIndexersHandler<'_, '_> { handle_table_events!( self, indexer_test_all_results, diff --git a/src/handlers/sonarr_handlers/library/add_series_handler.rs b/src/handlers/sonarr_handlers/library/add_series_handler.rs index ab5199b..b50ab9d 100644 --- a/src/handlers/sonarr_handlers/library/add_series_handler.rs +++ b/src/handlers/sonarr_handlers/library/add_series_handler.rs @@ -22,7 +22,7 @@ pub(super) struct AddSeriesHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> AddSeriesHandler<'a, 'b> { +impl AddSeriesHandler<'_, '_> { handle_table_events!( self, add_searched_series, diff --git a/src/handlers/sonarr_handlers/library/delete_series_handler.rs b/src/handlers/sonarr_handlers/library/delete_series_handler.rs index ff40805..e12f385 100644 --- a/src/handlers/sonarr_handlers/library/delete_series_handler.rs +++ b/src/handlers/sonarr_handlers/library/delete_series_handler.rs @@ -18,7 +18,7 @@ pub(super) struct DeleteSeriesHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> DeleteSeriesHandler<'a, 'b> { +impl DeleteSeriesHandler<'_, '_> { fn build_delete_series_params(&mut self) -> DeleteSeriesParams { let id = self.app.data.sonarr_data.series.current_selection().id; let delete_series_files = self.app.data.sonarr_data.delete_series_files; diff --git a/src/handlers/sonarr_handlers/library/edit_series_handler.rs b/src/handlers/sonarr_handlers/library/edit_series_handler.rs index 3dfa705..c8047e5 100644 --- a/src/handlers/sonarr_handlers/library/edit_series_handler.rs +++ b/src/handlers/sonarr_handlers/library/edit_series_handler.rs @@ -20,7 +20,7 @@ pub(super) struct EditSeriesHandler<'a, 'b> { context: Option, } -impl<'a, 'b> EditSeriesHandler<'a, 'b> { +impl EditSeriesHandler<'_, '_> { fn build_edit_series_params(&mut self) -> EditSeriesParams { let edit_series_modal = self .app diff --git a/src/handlers/sonarr_handlers/library/episode_details_handler.rs b/src/handlers/sonarr_handlers/library/episode_details_handler.rs index fdb8ca4..36370aa 100644 --- a/src/handlers/sonarr_handlers/library/episode_details_handler.rs +++ b/src/handlers/sonarr_handlers/library/episode_details_handler.rs @@ -20,7 +20,7 @@ pub(super) struct EpisodeDetailsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> EpisodeDetailsHandler<'a, 'b> { +impl EpisodeDetailsHandler<'_, '_> { handle_table_events!( self, episode_history, diff --git a/src/handlers/sonarr_handlers/library/mod.rs b/src/handlers/sonarr_handlers/library/mod.rs index a003821..870876e 100644 --- a/src/handlers/sonarr_handlers/library/mod.rs +++ b/src/handlers/sonarr_handlers/library/mod.rs @@ -44,7 +44,7 @@ pub(super) struct LibraryHandler<'a, 'b> { context: Option, } -impl<'a, 'b> LibraryHandler<'a, 'b> { +impl LibraryHandler<'_, '_> { handle_table_events!(self, series, self.app.data.sonarr_data.series, Series); } diff --git a/src/handlers/sonarr_handlers/library/season_details_handler.rs b/src/handlers/sonarr_handlers/library/season_details_handler.rs index 083c8a2..bf041b5 100644 --- a/src/handlers/sonarr_handlers/library/season_details_handler.rs +++ b/src/handlers/sonarr_handlers/library/season_details_handler.rs @@ -25,7 +25,7 @@ pub(super) struct SeasonDetailsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> SeasonDetailsHandler<'a, 'b> { +impl SeasonDetailsHandler<'_, '_> { handle_table_events!( self, episodes, diff --git a/src/handlers/sonarr_handlers/library/series_details_handler.rs b/src/handlers/sonarr_handlers/library/series_details_handler.rs index 2613a9f..52beadb 100644 --- a/src/handlers/sonarr_handlers/library/series_details_handler.rs +++ b/src/handlers/sonarr_handlers/library/series_details_handler.rs @@ -23,7 +23,7 @@ pub(super) struct SeriesDetailsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> SeriesDetailsHandler<'a, 'b> { +impl SeriesDetailsHandler<'_, '_> { handle_table_events!(self, season, self.app.data.sonarr_data.seasons, Season); handle_table_events!( self, diff --git a/src/handlers/sonarr_handlers/root_folders/mod.rs b/src/handlers/sonarr_handlers/root_folders/mod.rs index 37149a8..5bd51cb 100644 --- a/src/handlers/sonarr_handlers/root_folders/mod.rs +++ b/src/handlers/sonarr_handlers/root_folders/mod.rs @@ -21,7 +21,7 @@ pub(super) struct RootFoldersHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> RootFoldersHandler<'a, 'b> { +impl RootFoldersHandler<'_, '_> { handle_table_events!( self, root_folders, diff --git a/src/handlers/sonarr_handlers/system/system_details_handler.rs b/src/handlers/sonarr_handlers/system/system_details_handler.rs index a02b3c8..a9786f6 100644 --- a/src/handlers/sonarr_handlers/system/system_details_handler.rs +++ b/src/handlers/sonarr_handlers/system/system_details_handler.rs @@ -19,7 +19,7 @@ pub(super) struct SystemDetailsHandler<'a, 'b> { _context: Option, } -impl<'a, 'b> SystemDetailsHandler<'a, 'b> { +impl SystemDetailsHandler<'_, '_> { fn extract_task_name(&self) -> SonarrTaskName { self .app diff --git a/src/handlers/table_handler_tests.rs b/src/handlers/table_handler_tests.rs index 265c173..c872147 100644 --- a/src/handlers/table_handler_tests.rs +++ b/src/handlers/table_handler_tests.rs @@ -89,7 +89,7 @@ mod tests { fn handle_char_key_event(&mut self) {} } - impl<'a, 'b> TableHandlerUnit<'a, 'b> { + impl TableHandlerUnit<'_, '_> { handle_table_events!(self, movies, self.app.data.radarr_data.movies, Movie); } diff --git a/src/main.rs b/src/main.rs index a047046..5bb3a07 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -#![warn(rust_2018_idioms)] +#![warn(rust_2021_compatibility)] use anyhow::Result; use std::panic::PanicHookInfo; @@ -13,7 +13,7 @@ use crossterm::execute; use crossterm::terminal::{ disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; -use log::{error, warn}; +use log::{debug, error, warn}; use network::NetworkTrait; use ratatui::backend::CrosstermBackend; use ratatui::Terminal; @@ -93,6 +93,7 @@ async fn main() -> Result<()> { confy::load("managarr", "config")? }; let spinner_disabled = args.disable_spinner; + debug!("Managarr loaded using config: {config:?}"); config.validate(); let reqwest_client = build_network_client(&config); let (sync_network_tx, sync_network_rx) = mpsc::channel(500); diff --git a/src/models/mod.rs b/src/models/mod.rs index ba2a3f9..e454d3a 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -363,7 +363,7 @@ where } #[cfg(test)] -impl<'a, T> BlockSelectionState<'a, T> +impl BlockSelectionState<'_, T> where T: Sized + Clone + Copy + Default, { diff --git a/src/models/servarr_data/radarr/radarr_data.rs b/src/models/servarr_data/radarr/radarr_data.rs index d5ae110..11b8b1f 100644 --- a/src/models/servarr_data/radarr/radarr_data.rs +++ b/src/models/servarr_data/radarr/radarr_data.rs @@ -71,7 +71,7 @@ pub struct RadarrData<'a> { pub add_list_exclusion: bool, } -impl<'a> RadarrData<'a> { +impl RadarrData<'_> { pub fn reset_delete_movie_preferences(&mut self) { self.delete_movie_files = false; self.add_list_exclusion = false; diff --git a/src/models/servarr_data/sonarr/sonarr_data.rs b/src/models/servarr_data/sonarr/sonarr_data.rs index 04bab77..f456cbd 100644 --- a/src/models/servarr_data/sonarr/sonarr_data.rs +++ b/src/models/servarr_data/sonarr/sonarr_data.rs @@ -76,7 +76,7 @@ pub struct SonarrData<'a> { pub version: String, } -impl<'a> SonarrData<'a> { +impl SonarrData<'_> { pub fn reset_delete_series_preferences(&mut self) { self.delete_series_files = false; self.add_list_exclusion = false; diff --git a/src/network/mod.rs b/src/network/mod.rs index 92b4f98..2571ba7 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -52,7 +52,7 @@ pub struct Network<'a, 'b> { } #[async_trait] -impl<'a, 'b> NetworkTrait for Network<'a, 'b> { +impl NetworkTrait for Network<'_, '_> { async fn handle_network_event(&mut self, network_event: NetworkEvent) -> Result { let resp = match network_event { NetworkEvent::Radarr(radarr_event) => self diff --git a/src/network/radarr_network.rs b/src/network/radarr_network.rs index 6dcaaf0..757cbc4 100644 --- a/src/network/radarr_network.rs +++ b/src/network/radarr_network.rs @@ -134,7 +134,7 @@ impl From for NetworkEvent { } } -impl<'a, 'b> Network<'a, 'b> { +impl Network<'_, '_> { pub async fn handle_radarr_event( &mut self, radarr_event: RadarrEvent, diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index ee625ff..de1aed6 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -157,7 +157,7 @@ impl From for NetworkEvent { } } -impl<'a, 'b> Network<'a, 'b> { +impl Network<'_, '_> { pub async fn handle_sonarr_event( &mut self, sonarr_event: SonarrEvent, diff --git a/src/ui/styles.rs b/src/ui/styles.rs index 6d5e055..86f7233 100644 --- a/src/ui/styles.rs +++ b/src/ui/styles.rs @@ -32,7 +32,7 @@ where fn warning(self) -> T; } -impl<'a, T, U> ManagarrStyle<'a, T> for U +impl ManagarrStyle<'_, T> for U where U: Styled, T: Default, diff --git a/src/ui/widgets/button.rs b/src/ui/widgets/button.rs index 2c3524d..1de99e5 100644 --- a/src/ui/widgets/button.rs +++ b/src/ui/widgets/button.rs @@ -20,7 +20,7 @@ pub struct Button<'a> { is_selected: bool, } -impl<'a> Button<'a> { +impl Button<'_> { fn render_button_with_icon(self, area: Rect, buf: &mut Buffer) { let [title_area, icon_area] = Layout::horizontal([ Constraint::Length(self.title.len() as u16), @@ -69,7 +69,7 @@ impl<'a> Button<'a> { } } -impl<'a> Widget for Button<'a> { +impl Widget for Button<'_> { fn render(self, area: Rect, buf: &mut Buffer) where Self: Sized, diff --git a/src/ui/widgets/checkbox.rs b/src/ui/widgets/checkbox.rs index a3b4f81..35bc0d1 100644 --- a/src/ui/widgets/checkbox.rs +++ b/src/ui/widgets/checkbox.rs @@ -49,7 +49,7 @@ impl<'a> Checkbox<'a> { } } -impl<'a> Widget for Checkbox<'a> { +impl Widget for Checkbox<'_> { fn render(self, area: Rect, buf: &mut Buffer) { self.render_checkbox(area, buf); } diff --git a/src/ui/widgets/confirmation_prompt.rs b/src/ui/widgets/confirmation_prompt.rs index f026b1b..70f382b 100644 --- a/src/ui/widgets/confirmation_prompt.rs +++ b/src/ui/widgets/confirmation_prompt.rs @@ -26,7 +26,7 @@ pub struct ConfirmationPrompt<'a> { yes_no_highlighted: bool, } -impl<'a> ConfirmationPrompt<'a> { +impl ConfirmationPrompt<'_> { pub fn new() -> Self { Self { title: "", @@ -135,7 +135,7 @@ impl<'a> ConfirmationPrompt<'a> { } } -impl<'a> Widget for ConfirmationPrompt<'a> { +impl Widget for ConfirmationPrompt<'_> { fn render(self, area: Rect, buf: &mut Buffer) { if self.checkboxes.is_some() { self.render_confirmation_prompt_with_checkboxes(area, buf); diff --git a/src/ui/widgets/input_box.rs b/src/ui/widgets/input_box.rs index e0ec7e9..da32978 100644 --- a/src/ui/widgets/input_box.rs +++ b/src/ui/widgets/input_box.rs @@ -96,7 +96,7 @@ impl<'a> InputBox<'a> { } } -impl<'a> Widget for InputBox<'a> { +impl Widget for InputBox<'_> { fn render(self, area: Rect, buf: &mut Buffer) where Self: Sized, @@ -105,7 +105,7 @@ impl<'a> Widget for InputBox<'a> { } } -impl<'a> WidgetRef for InputBox<'a> { +impl WidgetRef for InputBox<'_> { fn render_ref(&self, area: Rect, buf: &mut Buffer) { self.render_input_box(area, buf); } diff --git a/src/ui/widgets/input_box_popup.rs b/src/ui/widgets/input_box_popup.rs index 8e92a38..9edd27b 100644 --- a/src/ui/widgets/input_box_popup.rs +++ b/src/ui/widgets/input_box_popup.rs @@ -53,7 +53,7 @@ impl<'a> InputBoxPopup<'a> { } } -impl<'a> WidgetRef for InputBoxPopup<'a> { +impl WidgetRef for InputBoxPopup<'_> { fn render_ref(&self, area: Rect, buf: &mut Buffer) { self.render_popup(area, buf); } diff --git a/src/ui/widgets/loading_block.rs b/src/ui/widgets/loading_block.rs index f6d5433..bcac243 100644 --- a/src/ui/widgets/loading_block.rs +++ b/src/ui/widgets/loading_block.rs @@ -30,7 +30,7 @@ impl<'a> LoadingBlock<'a> { } } -impl<'a> Widget for LoadingBlock<'a> { +impl Widget for LoadingBlock<'_> { fn render(self, area: Rect, buf: &mut Buffer) { self.render_loading_block(area, buf); } diff --git a/src/ui/widgets/message.rs b/src/ui/widgets/message.rs index 3cfc8f6..d46eb8e 100644 --- a/src/ui/widgets/message.rs +++ b/src/ui/widgets/message.rs @@ -42,7 +42,7 @@ impl<'a> Message<'a> { } } -impl<'a> Widget for Message<'a> { +impl Widget for Message<'_> { fn render(self, area: Rect, buf: &mut Buffer) { self.render_message(area, buf); } diff --git a/src/ui/widgets/popup.rs b/src/ui/widgets/popup.rs index 6d63126..7c7cddb 100644 --- a/src/ui/widgets/popup.rs +++ b/src/ui/widgets/popup.rs @@ -129,7 +129,7 @@ impl<'a, T: Widget> Popup<'a, T> { } } -impl<'a, T: Widget> Widget for Popup<'a, T> { +impl Widget for Popup<'_, T> { fn render(self, area: Rect, buf: &mut Buffer) { self.render_popup(area, buf); } From 319e5f1ac253e4c7a48020df1eccb1a425235f2f Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Wed, 19 Feb 2025 15:44:55 -0700 Subject: [PATCH 4/6] test: Added remaining unit tests for the deserialize_optional_env_var deserialization functions --- src/app/app_tests.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/app/app_tests.rs b/src/app/app_tests.rs index 857fa46..c272980 100644 --- a/src/app/app_tests.rs +++ b/src/app/app_tests.rs @@ -365,6 +365,97 @@ mod tests { std::env::remove_var("TEST_VAR_DESERIALIZE"); } + #[test] + fn test_deserialize_optional_env_var_is_present() { + std::env::set_var("TEST_VAR_DESERIALIZE_OPTION", "localhost"); + let yaml_data = r#" + host: ${TEST_VAR_DESERIALIZE_OPTION} + api_token: "test123" + "#; + + let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); + + assert_eq!(config.host, Some("localhost".to_string())); + std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION"); + } + + #[test] + fn test_deserialize_optional_env_var_does_not_overwrite_non_env_value() { + std::env::set_var("TEST_VAR_DESERIALIZE_OPTION", "localhost"); + let yaml_data = r#" + host: www.example.com + api_token: "test123" + "#; + + let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); + + assert_eq!(config.host, Some("www.example.com".to_string())); + std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION"); + } + + #[test] + fn test_deserialize_optional_env_var_empty() { + let yaml_data = r#" + api_token: "test123" + "#; + + let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); + + assert_eq!(config.port, None); + } + + #[test] + fn test_deserialize_optional_u16_env_var_is_present() { + std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_U16", "1"); + let yaml_data = r#" + port: ${TEST_VAR_DESERIALIZE_OPTION_U16} + api_token: "test123" + "#; + + let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); + + assert_eq!(config.port, Some(1)); + std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_U16"); + } + + #[test] + fn test_deserialize_optional_u16_env_var_does_not_overwrite_non_env_value() { + std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_U16", "1"); + let yaml_data = r#" + port: 1234 + api_token: "test123" + "#; + + let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); + + assert_eq!(config.port, Some(1234)); + std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_U16"); + } + + #[test] + fn test_deserialize_optional_u16_env_var_invalid_number() { + let yaml_data = r#" + port: "hi" + api_token: "test123" + "#; + let result: Result = serde_yaml::from_str(yaml_data); + + assert!(result.is_err()); + let err = result.unwrap_err().to_string(); + assert!(err.contains("invalid digit found in string")); + } + + #[test] + fn test_deserialize_optional_u16_env_var_empty() { + let yaml_data = r#" + api_token: "test123" + "#; + + let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); + + assert_eq!(config.port, None); + } + #[test] fn test_interpolate_env_vars() { std::env::set_var("TEST_VAR_INTERPOLATION", "testing"); @@ -410,6 +501,7 @@ mod tests { ); } + #[test] fn test_servarr_config_redacted_debug() { let host = "localhost".to_owned(); let port = 1234; From 5164d814923e3fc422c1023f8e072ed8023832f1 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Wed, 19 Feb 2025 15:59:31 -0700 Subject: [PATCH 5/6] test: Fix a potential race condition happening with parallel tests --- src/app/app_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/app_tests.rs b/src/app/app_tests.rs index c272980..1afc80a 100644 --- a/src/app/app_tests.rs +++ b/src/app/app_tests.rs @@ -420,7 +420,7 @@ mod tests { #[test] fn test_deserialize_optional_u16_env_var_does_not_overwrite_non_env_value() { - std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_U16", "1"); + std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_U16_UNUSED", "1"); let yaml_data = r#" port: 1234 api_token: "test123" @@ -429,7 +429,7 @@ mod tests { let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); assert_eq!(config.port, Some(1234)); - std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_U16"); + std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_U16_UNUSED"); } #[test] From 105c8f3a8239fc466f723289e39443fe795131da Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Wed, 19 Feb 2025 17:27:56 -0700 Subject: [PATCH 6/6] test: Hopefully the final environment variable name fix to correct all race conditions with parallel tests --- src/app/app_tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/app_tests.rs b/src/app/app_tests.rs index 1afc80a..6be41e6 100644 --- a/src/app/app_tests.rs +++ b/src/app/app_tests.rs @@ -381,7 +381,7 @@ mod tests { #[test] fn test_deserialize_optional_env_var_does_not_overwrite_non_env_value() { - std::env::set_var("TEST_VAR_DESERIALIZE_OPTION", "localhost"); + std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_NO_OVERWRITE", "localhost"); let yaml_data = r#" host: www.example.com api_token: "test123" @@ -390,7 +390,7 @@ mod tests { let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap(); assert_eq!(config.host, Some("www.example.com".to_string())); - std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION"); + std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_NO_OVERWRITE"); } #[test] @@ -468,9 +468,9 @@ mod tests { #[test] fn test_interpolate_env_vars_defaults_to_original_string_if_not_in_yaml_interpolation_format() { - let var = interpolate_env_vars("TEST_VAR_INTERPOLATION"); + let var = interpolate_env_vars("TEST_VAR_INTERPOLATION_NON_YAML"); - assert_str_eq!(var, "TEST_VAR_INTERPOLATION"); + assert_str_eq!(var, "TEST_VAR_INTERPOLATION_NON_YAML"); } #[test]