feat: add magic meta plugin implementation

Co-authored-by: aider (openai/andrew/openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
This commit is contained in:
Andrew Phillips
2025-08-16 14:51:30 -03:00
parent 28959a357c
commit 151ec151db
2 changed files with 104 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ pub mod system;
use crate::meta_plugin::program::MetaPluginProgram; use crate::meta_plugin::program::MetaPluginProgram;
use crate::meta_plugin::digest::{DigestSha256MetaPlugin, ReadTimeMetaPlugin, ReadRateMetaPlugin}; use crate::meta_plugin::digest::{DigestSha256MetaPlugin, ReadTimeMetaPlugin, ReadRateMetaPlugin};
use crate::meta_plugin::system::{CwdMetaPlugin, BinaryMetaPlugin, UidMetaPlugin, UserMetaPlugin, GidMetaPlugin, GroupMetaPlugin, ShellMetaPlugin, ShellPidMetaPlugin, KeepPidMetaPlugin, HostnameMetaPlugin, FullHostnameMetaPlugin}; use crate::meta_plugin::system::{CwdMetaPlugin, BinaryMetaPlugin, UidMetaPlugin, UserMetaPlugin, GidMetaPlugin, GroupMetaPlugin, ShellMetaPlugin, ShellPidMetaPlugin, KeepPidMetaPlugin, HostnameMetaPlugin, FullHostnameMetaPlugin};
use crate::meta_plugin::magic::MagicMetaPlugin;
#[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString)] #[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString)]
#[strum(ascii_case_insensitive)] #[strum(ascii_case_insensitive)]
@@ -18,6 +19,9 @@ pub enum MetaPluginType {
FileMagic, FileMagic,
FileMime, FileMime,
FileEncoding, FileEncoding,
MagicFileType,
MagicMimeType,
MagicMimeEncoding,
LineCount, LineCount,
WordCount, WordCount,
Cwd, Cwd,
@@ -83,6 +87,9 @@ pub fn get_meta_plugin(meta_plugin_type: MetaPluginType) -> Box<dyn MetaPlugin>
MetaPluginType::FileMagic => Box::new(MetaPluginProgram::new("file", vec!["-bE", "-"], "file_magic".to_string(), true)), MetaPluginType::FileMagic => Box::new(MetaPluginProgram::new("file", vec!["-bE", "-"], "file_magic".to_string(), true)),
MetaPluginType::FileMime => Box::new(MetaPluginProgram::new("file", vec!["-b", "--mime-type", "-"], "file_mime".to_string(), true)), MetaPluginType::FileMime => Box::new(MetaPluginProgram::new("file", vec!["-b", "--mime-type", "-"], "file_mime".to_string(), true)),
MetaPluginType::FileEncoding => Box::new(MetaPluginProgram::new("file", vec!["-b", "--mime-encoding", "-"], "file_encoding".to_string(), true)), MetaPluginType::FileEncoding => Box::new(MetaPluginProgram::new("file", vec!["-b", "--mime-encoding", "-"], "file_encoding".to_string(), true)),
MetaPluginType::MagicFileType => Box::new(MagicMetaPlugin::new_file_type()),
MetaPluginType::MagicMimeType => Box::new(MagicMetaPlugin::new_mime_type()),
MetaPluginType::MagicMimeEncoding => Box::new(MagicMetaPlugin::new_mime_encoding()),
MetaPluginType::LineCount => Box::new(MetaPluginProgram::new("wc", vec!["-l"], "line_count".to_string(), true)), MetaPluginType::LineCount => Box::new(MetaPluginProgram::new("wc", vec!["-l"], "line_count".to_string(), true)),
MetaPluginType::WordCount => Box::new(MetaPluginProgram::new("wc", vec!["-w"], "word_count".to_string(), true)), MetaPluginType::WordCount => Box::new(MetaPluginProgram::new("wc", vec!["-w"], "word_count".to_string(), true)),
MetaPluginType::Cwd => Box::new(CwdMetaPlugin::new()), MetaPluginType::Cwd => Box::new(CwdMetaPlugin::new()),

View File

@@ -0,0 +1,97 @@
use anyhow::Result;
use magic::{Cookie, CookieFlags};
use std::io;
use std::io::Write;
use crate::meta_plugin::MetaPlugin;
#[derive(Debug, Clone)]
pub struct MagicMetaPlugin {
buffer: Vec<u8>,
meta_name: String,
cookie_flags: CookieFlags,
}
impl MagicMetaPlugin {
pub fn new_file_type() -> MagicMetaPlugin {
MagicMetaPlugin {
buffer: Vec::new(),
meta_name: "magic_file_type".to_string(),
cookie_flags: CookieFlags::NONE,
}
}
pub fn new_mime_type() -> MagicMetaPlugin {
MagicMetaPlugin {
buffer: Vec::new(),
meta_name: "magic_mime_type".to_string(),
cookie_flags: CookieFlags::MIME_TYPE,
}
}
pub fn new_mime_encoding() -> MagicMetaPlugin {
MagicMetaPlugin {
buffer: Vec::new(),
meta_name: "magic_mime_encoding".to_string(),
cookie_flags: CookieFlags::MIME_ENCODING,
}
}
}
impl MetaPlugin for MagicMetaPlugin {
fn is_internal(&self) -> bool {
true
}
fn create(&self) -> Result<Box<dyn Write>> {
// For meta plugins, we don't actually create a writer since we're buffering data internally
Ok(Box::new(DummyWriter))
}
fn finalize(&mut self) -> io::Result<String> {
let cookie = Cookie::open(self.cookie_flags)
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to open magic cookie: {}", e)))?;
cookie.load(&Default::default())
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to load magic database: {}", e)))?;
let result = cookie.buffer(&self.buffer)
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to analyze buffer: {}", e)))?;
// Clean up the result - remove extra whitespace and take first part if needed
let trimmed = result.trim();
// For some magic results, we might want just the first part before semicolon or comma
let cleaned = if trimmed.contains(';') {
trimmed.split(';').next().unwrap_or(trimmed).trim()
} else if trimmed.contains(',') && self.meta_name.contains("mime") {
trimmed.split(',').next().unwrap_or(trimmed).trim()
} else {
trimmed
};
Ok(cleaned.to_string())
}
fn update(&mut self, data: &[u8]) {
self.buffer.extend_from_slice(data);
}
fn meta_name(&mut self) -> String {
self.meta_name.clone()
}
}
// Dummy writer that implements Write but doesn't do anything
// This is needed to satisfy the MetaPlugin trait requirements
struct DummyWriter;
impl Write for DummyWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}