From 52dc8cea32512d76332b99a8c4d8ea6366cd7be8 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Thu, 28 Aug 2025 13:11:19 -0300 Subject: [PATCH] feat: update dependencies and remove binary and command meta plugins --- Cargo.lock | 52 ++++++++- src/meta_plugin/binary.rs | 149 ------------------------ src/meta_plugin/command.rs | 227 ------------------------------------- src/modes/diff.rs | 35 +++--- src/modes/status.rs | 14 ++- 5 files changed, 78 insertions(+), 399 deletions(-) delete mode 100644 src/meta_plugin/binary.rs delete mode 100644 src/meta_plugin/command.rs diff --git a/Cargo.lock b/Cargo.lock index 1f785d2..fb24d0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,7 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" dependencies = [ "async-trait", - "convert_case", + "convert_case 0.6.0", "json5", "nom", "pathdiff", @@ -444,6 +444,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -561,6 +570,28 @@ dependencies = [ "syn 2.0.105", ] +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case 0.7.1", + "proc-macro2", + "quote", + "syn 2.0.105", + "unicode-xid", +] + [[package]] name = "digest" version = "0.9.0" @@ -1331,6 +1362,7 @@ dependencies = [ "chrono", "clap", "config", + "derive_more", "directories", "dns-lookup", "enum-map", @@ -1361,6 +1393,7 @@ dependencies = [ "serde_json", "serde_yaml", "sha2 0.10.9", + "smart-default", "stderrlog", "strum", "strum_macros", @@ -2290,6 +2323,17 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "smart-default" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.105", +] + [[package]] name = "socket2" version = "0.6.0" @@ -2741,6 +2785,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unsafe-libyaml" version = "0.2.11" diff --git a/src/meta_plugin/binary.rs b/src/meta_plugin/binary.rs deleted file mode 100644 index e0ce002..0000000 --- a/src/meta_plugin/binary.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::common::is_binary::is_binary; -use crate::common::PIPESIZE; -use crate::meta_plugin::{MetaPlugin, MetaPluginResponse, MetaPluginType}; - -#[derive(Debug, Clone, Default)] -pub struct BinaryMetaPlugin { - buffer: Vec, - max_buffer_size: usize, - is_finalized: bool, - base: crate::meta_plugin::BaseMetaPlugin, -} - -impl BinaryMetaPlugin { - pub fn new( - options: Option>, - outputs: Option>, - ) -> BinaryMetaPlugin { - let mut base = crate::meta_plugin::BaseMetaPlugin::new(); - - // Initialize with helper function - base.initialize_plugin( - &["binary"], - options, - outputs, - ); - - let max_buffer_size = base.options.get("max_buffer_size") - .and_then(|v| v.as_u64()) - .unwrap_or(PIPESIZE as u64) as usize; - - BinaryMetaPlugin { - buffer: Vec::new(), - max_buffer_size, - is_finalized: false, - base, - } - } - -} - -impl MetaPlugin for BinaryMetaPlugin { - fn is_finalized(&self) -> bool { - self.is_finalized - } - - fn set_finalized(&mut self, finalized: bool) { - self.is_finalized = finalized; - } - - fn update(&mut self, data: &[u8]) -> MetaPluginResponse { - // If already finalized, don't process more data - if self.is_finalized { - return MetaPluginResponse { - metadata: Vec::new(), - is_finalized: true, - }; - } - - // Calculate how much data we can still accept - let remaining_capacity = self.max_buffer_size.saturating_sub(self.buffer.len()); - if remaining_capacity > 0 { - // Determine how much data to copy - let bytes_to_take = std::cmp::min(data.len(), remaining_capacity); - - // Add data to our buffer - self.buffer.extend_from_slice(&data[..bytes_to_take]); - } - - // If we've reached our buffer limit, return metadata - let mut metadata = Vec::new(); - if self.buffer.len() >= self.max_buffer_size { - let is_binary_result = is_binary(&self.buffer); - let value = if is_binary_result { "true".to_string() } else { "false".to_string() }; - - // Use process_metadata_outputs to handle output mapping - if let Some(meta_data) = crate::meta_plugin::process_metadata_outputs( - "binary", - serde_yaml::Value::String(value), - self.base.outputs() - ) { - metadata.push(meta_data); - } - - // Mark as finalized - self.is_finalized = true; - } - - let is_finalized = !metadata.is_empty(); - MetaPluginResponse { - metadata, - is_finalized, - } - } - - fn finalize(&mut self) -> MetaPluginResponse { - // If already finalized, don't process again - if self.is_finalized { - return MetaPluginResponse { - metadata: Vec::new(), - is_finalized: true, - }; - } - - let mut metadata = Vec::new(); - - // Save the binary detection result when finalizing - let is_binary_result = is_binary(&self.buffer); - let value = if is_binary_result { "true".to_string() } else { "false".to_string() }; - - // Use process_metadata_outputs to handle output mapping - if let Some(meta_data) = crate::meta_plugin::process_metadata_outputs( - "binary", - serde_yaml::Value::String(value), - self.base.outputs() - ) { - metadata.push(meta_data); - } - - // Mark as finalized - self.is_finalized = true; - - MetaPluginResponse { - metadata, - is_finalized: true, - } - } - - fn meta_type(&self) -> MetaPluginType { - MetaPluginType::Binary - } - - fn outputs(&self) -> &std::collections::HashMap { - self.base.outputs() - } - - fn outputs_mut(&mut self) -> &mut std::collections::HashMap { - self.base.outputs_mut() - } - - - fn options(&self) -> &std::collections::HashMap { - self.base.options() - } - - fn options_mut(&mut self) -> &mut std::collections::HashMap { - self.base.options_mut() - } - -} diff --git a/src/meta_plugin/command.rs b/src/meta_plugin/command.rs deleted file mode 100644 index 01228bf..0000000 --- a/src/meta_plugin/command.rs +++ /dev/null @@ -1,227 +0,0 @@ -use log::*; -use std::io::Write; -use std::process::{Command, Stdio, Child}; -use which::which; - -use crate::meta_plugin::{MetaPlugin, MetaPluginResponse, MetaPluginType}; - -pub struct MetaPluginExec { - pub program: String, - pub args: Vec, - pub supported: bool, - pub split_whitespace: bool, - process: Option, - writer: Option>, - result: Option, - outputs: std::collections::HashMap, - options: std::collections::HashMap, -} - -// Manual Debug implementation because Box doesn't implement Debug -impl std::fmt::Debug for MetaPluginExec { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MetaPluginExec") - .field("program", &self.program) - .field("args", &self.args) - .field("supported", &self.supported) - .field("split_whitespace", &self.split_whitespace) - .field("process", &self.process) - .field("writer", &self.writer.as_ref().map(|_| "Box")) - .field("result", &self.result) - .field("outputs", &self.outputs) - .field("options", &self.options) - .finish() - } -} - - -impl MetaPluginExec { - pub fn new( - program: &str, - args: Vec<&str>, - meta_name: String, - split_whitespace: bool, - _options: Option>, - outputs: Option>, - ) -> MetaPluginExec { - let program_path = which(program); - let supported = program_path.is_ok(); - - // Start with default outputs - let mut final_outputs = std::collections::HashMap::new(); - final_outputs.insert(meta_name.clone(), serde_yaml::Value::String(meta_name.clone())); - if let Some(outs) = outputs { - for (key, value) in outs { - final_outputs.insert(key, value); - } - } - - // Start with default options - let mut final_options = std::collections::HashMap::new(); - if let Some(opts) = _options { - for (key, value) in opts { - final_options.insert(key, value); - } - } - - MetaPluginExec { - program: program_path.map_or_else(|_| program.to_string(), |p| p.to_string_lossy().to_string()), - args: args.iter().map(|s| s.to_string()).collect(), - supported, - split_whitespace, - process: None, - writer: None, - result: None, - outputs: final_outputs, - options: final_options, - } - } - -} - -impl MetaPlugin for MetaPluginExec { - fn is_supported(&self) -> bool { - self.supported - } - - fn is_internal(&self) -> bool { - false - } - - fn initialize(&mut self) -> MetaPluginResponse { - debug!("META: Initializing program plugin: {:?}", self); - - let program = self.program.clone(); - let args = self.args.clone(); - - debug!("META: Executing command: {:?} {:?}", program, args); - - let mut process = match Command::new(program.clone()) - .args(args.clone()) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - { - Ok(process) => process, - Err(e) => { - debug!("META: Failed to spawn process: {}", e); - return MetaPluginResponse { - metadata: Vec::new(), - is_finalized: true, - }; - } - }; - - let stdin = process.stdin.take().unwrap(); - self.writer = Some(Box::new(stdin)); - self.process = Some(process); - - MetaPluginResponse { - metadata: Vec::new(), - is_finalized: false, - } - } - - fn finalize(&mut self) -> MetaPluginResponse { - debug!("META: Finalizing program plugin"); - let mut metadata = Vec::new(); - - if let Some(process) = self.process.take() { - // Close stdin to signal end of input - drop(self.writer.take()); - - // Wait for the process to complete - let output = match process.wait_with_output() { - Ok(output) => output, - Err(e) => { - debug!("META: Failed to get process output: {}", e); - return MetaPluginResponse { - metadata: Vec::new(), - is_finalized: true, - }; - } - }; - - if output.status.success() { - // Process the output - let output_str = String::from_utf8_lossy(&output.stdout); - let result = if self.split_whitespace { - output_str.split_whitespace().next().unwrap_or("").to_string() - } else { - output_str.trim().to_string() - }; - - if !result.is_empty() { - debug!("META: Program output: {}", result); - self.result = Some(result.clone()); - - // Use process_metadata_outputs to handle output mapping - if let Some(meta_data) = crate::meta_plugin::process_metadata_outputs( - &self.meta_type().to_string(), - serde_yaml::Value::String(result), - &self.outputs - ) { - metadata.push(meta_data); - } - } - } else { - debug!("META: Program failed with status: {:?}", output.status); - let stderr = String::from_utf8_lossy(&output.stderr); - if !stderr.is_empty() { - debug!("META: Program stderr: {}", stderr); - } - } - } - - MetaPluginResponse { - metadata, - is_finalized: true, - } - } - - fn update(&mut self, data: &[u8]) -> MetaPluginResponse { - if let Some(ref mut writer) = self.writer { - if let Err(e) = writer.write_all(data) { - debug!("META: Failed to write to process stdin: {}", e); - } - } - MetaPluginResponse { - metadata: Vec::new(), - is_finalized: false, - } - } - - fn meta_type(&self) -> MetaPluginType { - MetaPluginType::Exec - } - - fn program_info(&self) -> Option<(&str, Vec<&str>)> { - if self.supported { - Some((&self.program, self.args.iter().map(|s| s.as_str()).collect())) - } else { - None - } - } - - fn outputs(&self) -> &std::collections::HashMap { - &self.outputs - } - - fn outputs_mut(&mut self) -> &mut std::collections::HashMap { - &mut self.outputs - } - - fn default_outputs(&self) -> Vec { - vec![self.meta_type().to_string()] - } - - - fn options(&self) -> &std::collections::HashMap { - &self.options - } - - fn options_mut(&mut self) -> &mut std::collections::HashMap { - &mut self.options - } -} diff --git a/src/modes/diff.rs b/src/modes/diff.rs index 146e90b..b26fbb6 100644 --- a/src/modes/diff.rs +++ b/src/modes/diff.rs @@ -4,6 +4,7 @@ use std::io::Read; use std::os::fd::FromRawFd; use crate::config; use crate::services::item_service::ItemService; +use log::debug; fn validate_diff_args(cmd: &mut Command, ids: &Vec, tags: &Vec) { if !tags.is_empty() { @@ -35,8 +36,8 @@ fn fetch_and_validate_items( .get_item(conn, ids[1]) .with_context(|| format!("Unable to find second item (ID: {}) in database", ids[1]))?; - log::debug!("MAIN: Found item A {:?}", item_a.item); - log::debug!("MAIN: Found item B {:?}", item_b.item); + debug!("MAIN: Found item A {:?}", item_a.item); + debug!("MAIN: Found item B {:?}", item_b.item); Ok((item_a, item_b)) } @@ -94,7 +95,7 @@ fn spawn_diff_process( fd_a_read: libc::c_int, fd_b_read: libc::c_int, ) -> Result { - log::debug!("MAIN: Creating child process for diff"); + debug!("MAIN: Creating child process for diff"); let mut diff_command = std::process::Command::new("diff"); diff_command .arg("-u") @@ -157,10 +158,10 @@ fn write_item_to_pipe( let mut reader = engine.open(item_path) .map_err(|e| anyhow::anyhow!("Failed to open item: {}", e))?; - log::debug!("THREAD: Sending item to diff"); + debug!("THREAD: Sending item to diff"); std::io::copy(&mut reader, &mut buffered_pipe_writer) .map_err(|e| anyhow::anyhow!("Failed to copy item to pipe: {}", e))?; - log::debug!("THREAD: Done sending item to diff"); + debug!("THREAD: Done sending item to diff"); Ok(()) } @@ -188,12 +189,12 @@ fn execute_diff_command( .take() .expect("BUG: Failed to capture diff stderr pipe"); - log::debug!("MAIN: Creating threads for diff I/O"); + debug!("MAIN: Creating threads for diff I/O"); // Thread to read diff's standard output let stdout_reader_thread = std::thread::spawn(move || { let mut output_buffer = Vec::new(); - log::debug!("STDOUT_READER: Reading diff stdout"); + debug!("STDOUT_READER: Reading diff stdout"); // child_stdout_pipe is a ChildStdout, which implements std::io::Read child_stdout_pipe .read_to_end(&mut output_buffer) @@ -204,7 +205,7 @@ fn execute_diff_command( // Thread to read diff's standard error let stderr_reader_thread = std::thread::spawn(move || { let mut error_buffer = Vec::new(); - log::debug!("STDERR_READER: Reading diff stderr"); + debug!("STDERR_READER: Reading diff stderr"); child_stderr_pipe .read_to_end(&mut error_buffer) .map_err(|e| anyhow::anyhow!("Failed to read diff stderr: {}", e)) @@ -238,7 +239,7 @@ fn handle_diff_output( match diff_status.code() { Some(0) => { // Exit code 0: No differences - log::debug!("MAIN: Diff successful, no differences found."); + debug!("MAIN: Diff successful, no differences found."); // Typically, diff -u doesn't print to stdout if no differences. // But if it did, it would be shown here. if !stdout_capture_result.is_empty() { @@ -247,7 +248,7 @@ fn handle_diff_output( } Some(1) => { // Exit code 1: Differences found - log::debug!("MAIN: Diff successful, differences found."); + debug!("MAIN: Diff successful, differences found."); println!("{}", String::from_utf8_lossy(&stdout_capture_result)); } Some(error_code) => { @@ -335,10 +336,10 @@ pub fn mode_diff( spawn_writer_thread(item_path_b.clone(), compression_type_b.clone(), fd_b_write); // Wait for writer threads to complete (meaning all input has been sent to diff) - log::debug!("MAIN: Waiting on writer thread for item A"); + debug!("MAIN: Waiting on writer thread for item A"); match writer_thread_a.join() { Ok(Ok(())) => { - log::debug!("MAIN: Writer thread for item A completed successfully."); + debug!("MAIN: Writer thread for item A completed successfully."); } Ok(Err(e)) => { return Err(anyhow::anyhow!("Writer thread for item A failed: {}", e)); @@ -352,10 +353,10 @@ pub fn mode_diff( } } - log::debug!("MAIN: Waiting on writer thread for item B"); + debug!("MAIN: Waiting on writer thread for item B"); match writer_thread_b.join() { Ok(Ok(())) => { - log::debug!("MAIN: Writer thread for item B completed successfully."); + debug!("MAIN: Writer thread for item B completed successfully."); } Ok(Err(e)) => { return Err(anyhow::anyhow!("Writer thread for item B failed: {}", e)); @@ -369,18 +370,18 @@ pub fn mode_diff( } } - log::debug!("MAIN: Done waiting on input-writer threads."); + debug!("MAIN: Done waiting on input-writer threads."); // Now that all input has been sent, the diff process will run to completion. // We can read its output. This will block until the process is finished. let (stdout_capture_result, stderr_capture_result) = execute_diff_command(&mut child_process)?; // wait for the diff child process to terminate. - log::debug!("MAIN: Waiting for diff child process to finish..."); + debug!("MAIN: Waiting for diff child process to finish..."); let diff_status = child_process .wait() .map_err(|e| anyhow::anyhow!("Failed to wait on diff command: {}", e))?; - log::debug!( + debug!( "MAIN: Diff child process finished with status: {}", diff_status ); diff --git a/src/modes/status.rs b/src/modes/status.rs index 1de8fcf..3dc4ff0 100644 --- a/src/modes/status.rs +++ b/src/modes/status.rs @@ -2,6 +2,7 @@ use clap::*; use is_terminal::IsTerminal; use std::path::PathBuf; use std::str::FromStr; +use log::debug; use crate::modes::common::{get_format_box_chars_no_border_line_separator, OutputFormat}; use crate::config; @@ -344,12 +345,12 @@ pub fn mode_status( data_path: PathBuf, db_path: PathBuf, ) -> Result<(), anyhow::Error> { - log::debug!("STATUS: Starting mode_status function"); + debug!("STATUS: Starting mode_status function"); // Determine which meta plugins would be enabled for a save operation - log::debug!("STATUS: Getting meta plugin types from settings"); + debug!("STATUS: Getting meta plugin types from settings"); let mut meta_plugin_types: Vec = crate::modes::common::settings_meta_plugin_types(_cmd, settings); - log::debug!("STATUS: Got {} meta plugin types", meta_plugin_types.len()); + debug!("STATUS: Got {} meta plugin types", meta_plugin_types.len()); // Always add the Digest plugin if not present if !meta_plugin_types.contains(&MetaPluginType::Digest) { @@ -364,9 +365,9 @@ pub fn mode_status( }; let output_format = crate::modes::common::settings_output_format(settings); - log::debug!("STATUS: About to call generate_status_info"); + debug!("STATUS: About to call generate_status_info"); let status_info = generate_status_info(data_path, db_path, &meta_plugin_types, enabled_compression_type); - log::debug!("STATUS: generate_status_info completed successfully"); + debug!("STATUS: generate_status_info completed successfully"); match output_format { OutputFormat::Table => { @@ -377,11 +378,14 @@ pub fn mode_status( println!("PATHS:"); build_path_table(&status_info.paths).printstd(); println!(); + println!("COMPRESSION:"); build_compression_table(&status_info.compression).printstd(); println!(); + println!("META PLUGINS AVAILABLE:"); build_meta_plugin_table(&status_info.meta_plugins).printstd(); + println!(); // Print META PLUGINS CONFIGURED if they exist if let Some(meta_plugins_table) = build_meta_plugins_configured_table(settings) {