use clap::*; use std::path::PathBuf; use std::str::FromStr; use log::debug; use crate::modes::common::OutputFormat; use crate::config; use crate::common::status::StatusInfo; use serde_json; use serde_yaml; use comfy_table::{Table, Cell, Attribute}; use crate::common::status::PathInfo; use crate::meta_plugin::MetaPluginType; use crate::meta_plugin::get_meta_plugin; fn build_path_table(path_info: &PathInfo) -> Table { let mut path_table = crate::modes::common::create_table(true); path_table.set_header(vec![ Cell::new("Type").add_attribute(Attribute::Bold), Cell::new("Path").add_attribute(Attribute::Bold), ]); path_table.add_row(vec!["Data", &path_info.data]); path_table.add_row(vec!["Database", &path_info.database]); path_table } fn build_config_table(settings: &config::Settings) -> Table { let mut config_table = crate::modes::common::create_table(true); config_table.set_header(vec![ Cell::new("Setting").add_attribute(Attribute::Bold), Cell::new("Value").add_attribute(Attribute::Bold), ]); // Add relevant configuration settings config_table.add_row(vec!["Directory", &settings.dir.to_string_lossy()]); config_table.add_row(vec!["Human Readable", &settings.human_readable.to_string()]); config_table.add_row(vec!["Quiet", &settings.quiet.to_string()]); if let Some(output_format) = &settings.output_format { config_table.add_row(vec!["Output Format", output_format]); } if let Some(compression) = settings.compression() { config_table.add_row(vec!["Compression", &compression]); } config_table } fn build_meta_plugins_configured_table(status_info: &StatusInfo) -> Option { let meta_plugins = status_info.configured_meta_plugins.as_ref()?; if meta_plugins.is_empty() { return None; } // Sort meta plugins by name let mut sorted_meta_plugins = meta_plugins.clone(); sorted_meta_plugins.sort_by(|a, b| a.name.cmp(&b.name)); let mut table = crate::modes::common::create_table(true); table.set_header(vec![ Cell::new("Plugin Name").add_attribute(Attribute::Bold), Cell::new("Options").add_attribute(Attribute::Bold), Cell::new("Outputs").add_attribute(Attribute::Bold), ]); for plugin_config in sorted_meta_plugins { // Create the plugin to get its default options let meta_plugin_type = match MetaPluginType::from_str(&plugin_config.name) { Ok(plugin_type) => plugin_type, Err(_) => continue, }; // First, create a default plugin to get its default options let default_plugin = get_meta_plugin( meta_plugin_type.clone(), None, None, ); // Start with the default options let mut effective_options = default_plugin.options().clone(); // Merge with the configured options for (key, value) in &plugin_config.options { effective_options.insert(key.clone(), value.clone()); } // Convert outputs from HashMap to HashMap let outputs_converted: std::collections::HashMap = plugin_config.outputs .iter() .map(|(k, v)| (k.clone(), serde_yaml::Value::String(v.clone()))) .collect(); // Create the actual plugin with merged options - the constructor will handle setting up outputs let actual_plugin = get_meta_plugin( meta_plugin_type.clone(), Some(effective_options.clone()), Some(outputs_converted), ); // Get the default plugin to see its default options let default_plugin = get_meta_plugin( meta_plugin_type.clone(), None, None, ); // Start with the default options let mut all_options = default_plugin.options().clone(); // Merge with the configured options for (key, value) in &effective_options { all_options.insert(key.clone(), value.clone()); } // Sort options by key and convert to a YAML string let mut sorted_options: Vec<_> = all_options.iter().collect(); sorted_options.sort_by(|a, b| a.0.cmp(b.0)); let sorted_options_map: std::collections::BTreeMap<_, _> = sorted_options.into_iter().collect(); let options_str = if sorted_options_map.is_empty() { "{}".to_string() } else { serde_yaml::to_string(&sorted_options_map) .unwrap_or_else(|_| "Unable to serialize options".to_string()) .trim() .to_string() }; // Show only non-null outputs from the plugin // Collect and sort outputs by their string representation let mut enabled_output_pairs = Vec::new(); for (key, value) in actual_plugin.outputs() { // Skip null values (disabled outputs) if value.is_null() { continue; } // Convert serde_yaml::Value to a string representation let value_str = match value { serde_yaml::Value::String(s) => s.clone(), serde_yaml::Value::Number(n) => n.to_string(), serde_yaml::Value::Bool(b) => b.to_string(), serde_yaml::Value::Null => "null".to_string(), serde_yaml::Value::Sequence(_) => { serde_yaml::to_string(value).unwrap_or_else(|_| "[]".to_string()) } serde_yaml::Value::Mapping(_) => { serde_yaml::to_string(value).unwrap_or_else(|_| "{}".to_string()) } serde_yaml::Value::Tagged(_) => { serde_yaml::to_string(value).unwrap_or_else(|_| "tagged".to_string()) } }; // Trim any extra whitespace from the serialized values let value_str = value_str.trim().to_string(); if key == &value_str { enabled_output_pairs.push((key.clone(), key.clone())); } else { enabled_output_pairs.push((key.clone(), format!("{}->{}", key, value_str))); } } // Sort outputs by their display value (second element of the tuple) enabled_output_pairs.sort_by(|a, b| a.1.cmp(&b.1)); // Join each output on a new line let outputs_str = if enabled_output_pairs.is_empty() { "{}".to_string() } else { enabled_output_pairs.into_iter() .map(|(_, display)| display) .collect::>() .join("\n") }; table.add_row(vec![ plugin_config.name.clone(), options_str, outputs_str, ]); } Some(table) } pub fn mode_status( cmd: &mut Command, settings: &config::Settings, data_path: PathBuf, db_path: PathBuf, ) -> Result<(), anyhow::Error> { debug!("STATUS: Starting mode_status function"); let status_service = crate::services::status_service::StatusService::new(); let output_format = crate::modes::common::settings_output_format(settings); debug!("STATUS: About to generate status info"); let status_info = status_service.generate_status(cmd, settings, data_path, db_path); debug!("STATUS: Status info generated successfully"); match output_format { OutputFormat::Table => { println!("CONFIG:"); println!("{}", build_config_table(settings)); println!(); println!("PATHS:"); println!("{}", build_path_table(&status_info.paths)); println!(); // Always try to print META PLUGINS CONFIGURED section using status_info if let Some(meta_plugins_table) = build_meta_plugins_configured_table(&status_info) { println!("META PLUGINS CONFIGURED:"); println!("{}", meta_plugins_table); println!(); } else { println!("META PLUGINS CONFIGURED:"); println!("No plugins configured"); println!(); } Ok(()) }, OutputFormat::Json => { // Create a subset for status info that includes everything println!("{}", serde_json::to_string_pretty(&status_info)?); Ok(()) }, OutputFormat::Yaml => { println!("{}", serde_yaml::to_string(&status_info)?); Ok(()) } } }