refactor: integrate digest functionality into meta plugins and remove digest_engine module

Co-authored-by: aider (openai/andrew.openrouter.qwen.qwen3-coder) <aider@aider.chat>
This commit is contained in:
Andrew Phillips
2025-07-28 17:31:23 -03:00
parent 4c8c6569a9
commit e51a902660
8 changed files with 26 additions and 220 deletions

View File

@@ -4,15 +4,16 @@
1. ALWAYS keep DESIGN.md updated with any architectural or design changes
2. ALWAYS keep project rules first in this document
3. Follow Rust naming conventions and idioms
4. Use anyhow for error handling throughout the codebase
5. Maintain comprehensive logging with the log crate
6. Write unit tests for critical functionality
7. Document public APIs with rustdoc comments
8. Keep modules focused on single responsibilities
9. Prefer composition over inheritance
10. Handle errors gracefully and provide meaningful error messages
11. Ensure code is safe and avoids unsafe blocks where possible
3. ALWAYS use git commands to remove or move files (`git rm`, `git mv`, etc.)
4. Follow Rust naming conventions and idioms
5. Use anyhow for error handling throughout the codebase
6. Maintain comprehensive logging with the log crate
7. Write unit tests for critical functionality
8. Document public APIs with rustdoc comments
9. Keep modules focused on single responsibilities
10. Prefer composition over inheritance
11. Handle errors gracefully and provide meaningful error messages
12. Ensure code is safe and avoids unsafe blocks where possible
## Code - Modules
@@ -45,11 +46,10 @@
- `compression_engine/none.rs` - No compression implementation
- `compression_engine/program.rs` - External program wrapper
### Digest Engine Module
- `digest_engine.rs` - Trait and type definitions
- `digest_engine/sha2.rs` - SHA-256 implementation
- `digest_engine/none.rs` - No digest implementation
- `digest_engine/program.rs` - External program wrapper
### Digest Functionality
- Digest functionality is now integrated into meta plugins
- SHA-256 and other digest algorithms are implemented as meta plugins
- External digest programs are supported through meta plugin program wrapper
### Meta Plugin Module
- `meta_plugin.rs` - Trait and type definitions

View File

@@ -20,7 +20,6 @@ extern crate lazy_static;
pub mod compression_engine;
pub mod db;
pub mod digest_engine;
pub mod plugins;
pub mod meta_plugin;
//pub mod item;

View File

@@ -8,8 +8,10 @@ use enum_map::enum_map;
use enum_map::{Enum, EnumMap};
pub mod program;
pub mod digest;
use crate::meta_plugin::program::MetaPluginProgram;
use crate::meta_plugin::digest::DigestSha256MetaPlugin;
use strum::IntoEnumIterator;

View File

@@ -3,7 +3,6 @@ use crate::compression_engine::CompressionType;
use crate::db::Item;
use crate::db::Meta;
use crate::db::store_meta;
use crate::digest_engine::DigestType;
use crate::meta_plugin::MetaPluginType;
use clap::Command;
use clap::error::ErrorKind;
@@ -100,7 +99,7 @@ pub fn get_format_box_chars_no_border_line_separator() -> TableFormat {
.build()
}
pub fn get_digest_type_meta(digest_type: DigestType) -> String {
pub fn get_digest_type_meta(digest_type: MetaPluginType) -> String {
format!("digest_{}", digest_type.to_string().to_lowercase())
}
@@ -123,7 +122,7 @@ pub fn store_item_meta_value(
pub fn store_item_digest_value(
conn: &mut Connection,
item: Item,
digest_type: DigestType,
digest_type: MetaPluginType,
digest_value: String,
) -> Result<(), anyhow::Error> {
// Save digest to meta
@@ -137,14 +136,14 @@ pub fn store_item_digest_value(
Ok(())
}
pub fn cmd_args_digest_type(cmd: &mut Command, args: &Args) -> DigestType {
pub fn cmd_args_digest_type(cmd: &mut Command, args: &Args) -> MetaPluginType {
let digest_name = args
.item
.digest
.clone()
.unwrap_or(DigestType::Sha256.to_string());
.unwrap_or(MetaPluginType::DigestSha256.to_string());
let digest_type_opt = DigestType::from_str(&digest_name);
let digest_type_opt = MetaPluginType::from_str(&digest_name);
if digest_type_opt.is_err() {
cmd.error(
ErrorKind::InvalidValue,

View File

@@ -41,9 +41,9 @@ pub fn mode_save(
// Convert digest type to meta plugin type
let digest_meta_plugin_type = match digest_type {
crate::digest_engine::DigestType::Sha256 => Some(MetaPluginType::DigestSha256),
crate::digest_engine::DigestType::Md5 => Some(MetaPluginType::DigestMd5),
crate::digest_engine::DigestType::None => None,
crate::meta_plugin::MetaPluginType::DigestSha256 => Some(MetaPluginType::DigestSha256),
crate::meta_plugin::MetaPluginType::DigestMd5 => Some(MetaPluginType::DigestMd5),
_ => None,
};
// Add digest meta plugin to the list if needed

View File

@@ -112,62 +112,6 @@ fn build_compression_table() -> Table {
compression_table
}
fn build_digest_table() -> Table {
use crate::digest_engine;
use crate::digest_engine::DIGEST_PROGRAMS;
use crate::digest_engine::DigestType;
use crate::digest_engine::program::DigestEngineProgram;
let mut digest_table = Table::new();
if std::io::stdout().is_terminal() {
digest_table.set_format(*FORMAT_BOX_CHARS_NO_BORDER_LINE_SEPARATOR);
} else {
digest_table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
}
digest_table.set_titles(row!(
b->"Type",
b->"Found",
b->"Default",
b->"Binary",
b->"Args"));
let default_type = digest_engine::default_digest_type();
for digest_type in DigestType::iter() {
let digest_program: DigestEngineProgram = match &DIGEST_PROGRAMS[digest_type.clone()] {
Some(digest_program) => digest_program.clone(),
None => DigestEngineProgram {
program: "".to_string(),
args: Vec::new(),
supported: true,
},
};
let is_default = digest_type == default_type;
digest_table.add_row(Row::new(vec![
Cell::new(&digest_type.to_string()),
match digest_program.supported {
true => Cell::new("Yes").with_style(Attr::ForegroundColor(color::GREEN)),
false => Cell::new("No").with_style(Attr::ForegroundColor(color::RED)),
},
match is_default {
true => Cell::new("Yes").with_style(Attr::ForegroundColor(color::GREEN)),
false => Cell::new("No"),
},
match digest_program.program.is_empty() {
true => {
Cell::new("<INTERNAL>").with_style(Attr::ForegroundColor(color::BRIGHT_BLACK))
}
false => Cell::new(&digest_program.program),
},
Cell::new(&digest_program.args.join(" ")),
]));
}
digest_table
}
fn build_meta_plugin_table() -> Table {
let mut meta_plugin_table = Table::new();
@@ -231,9 +175,6 @@ pub fn mode_status(
println!("COMPRESSION:");
build_compression_table().printstd();
println!();
println!("DIGEST:");
build_digest_table().printstd();
println!();
println!("META PLUGINS:");
build_meta_plugin_table().printstd();
Ok(())

View File

@@ -4,7 +4,7 @@ use std::str::FromStr;
use crate::compression_engine::{CompressionType, get_compression_engine};
use crate::db;
use crate::digest_engine;
use crate::meta_plugin;
use crate::modes::common::{cmd_args_digest_type, get_digest_type_meta, store_item_digest_value};
use clap::Command;
use clap::error::ErrorKind;
@@ -78,7 +78,7 @@ pub fn mode_update(
debug!("MAIN: Updating stream size of {:?}", item_path);
// Create and initialize digest engine
let mut digest_engine = digest_engine::get_digest_engine(digest_type.clone());
let mut digest_engine = meta_plugin::get_meta_plugin(digest_type.clone());
// Read file content and update digest
let mut reader = compression_engine.open(item_path)?;

View File

@@ -388,139 +388,4 @@ mod tests {
});
}
// Test: Compression functionality with different algorithms
#[test]
fn test_compression() {
with_temp_env(|data_dir| {
// Set the data directory for this test
let keep_cmd = format!("KEEP_DIR={} cargo run -- --verbose", data_dir.display());
// Test with no compression
let cmd = format!("echo {} | {} -c unknown unknown", INPUT_A, keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
!output.status.success(),
"Command succeeded when it should have failed: {} {}",
cmd,
output.status
);
// Test with no compression
let cmd = format!("echo {} | {} -c none none", INPUT_A, keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let cmd = format!("{} --get none", keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
assert!(
output_str.contains(INPUT_A),
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
cmd,
output_str,
INPUT_A
);
// Test with lz4 compression
let cmd = format!("echo {} | {} -c lz4 lz4", INPUT_A, keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let cmd = format!("{} --get lz4", keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
assert!(
output_str.contains(INPUT_A),
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
cmd,
output_str,
INPUT_A
);
// Test with gzip compression
let cmd = format!("echo {} | {} -c gzip gzip", INPUT_A, keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let cmd = format!("{} --get gzip", keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
assert!(
output_str.contains(INPUT_A),
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
cmd,
output_str,
INPUT_A
);
// Test with bzip2 compression
let cmd = format!("echo {} | {} -c bzip2 bzip2", INPUT_A, keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let cmd = format!("{} --get bzip2", keep_cmd);
println!("RUNNING: {}", cmd);
let output = run_sh(cmd.as_str());
assert!(
output.status.success(),
"Command failed: {} {}",
cmd,
output.status
);
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
assert!(
output_str.contains(INPUT_A),
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
cmd,
output_str,
INPUT_A
);
});
}
}