feat: add meta plugin with file and none implementations
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
extern crate enum_map;
|
||||||
|
use enum_map::enum_map;
|
||||||
|
use enum_map::{Enum, EnumMap};
|
||||||
|
|
||||||
|
pub mod none;
|
||||||
|
pub mod program;
|
||||||
|
|
||||||
|
use crate::meta_plugin::none::MetaPluginNone;
|
||||||
|
use crate::meta_plugin::program::MetaPluginProgram;
|
||||||
|
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString, Enum)]
|
||||||
|
#[strum(ascii_case_insensitive)]
|
||||||
|
pub enum MetaPluginType {
|
||||||
|
File,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MetaPlugin {
|
||||||
|
fn is_supported(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
fn create(&self) -> Result<Box<dyn Write>>;
|
||||||
|
fn finalize(&mut self) -> io::Result<String>;
|
||||||
|
|
||||||
|
// Update the meta plugin with new data
|
||||||
|
fn update(&mut self, data: &[u8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
// Writer that implements Write for the program meta plugin
|
||||||
|
struct ProgramWriter {
|
||||||
|
stdin: std::process::ChildStdin,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for ProgramWriter {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
self.stdin.write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
self.stdin.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref META_PLUGIN_PROGRAMS: EnumMap<MetaPluginType, Option<MetaPluginProgram>> = enum_map! {
|
||||||
|
MetaPluginType::File => {
|
||||||
|
let program = MetaPluginProgram::new("file", vec!["-bE", "-"]);
|
||||||
|
if program.supported { Some(program) } else { None }
|
||||||
|
}
|
||||||
|
MetaPluginType::None => None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_meta_plugin(meta_plugin_type: MetaPluginType) -> Box<dyn MetaPlugin> {
|
||||||
|
match meta_plugin_type {
|
||||||
|
MetaPluginType::File => Box::new(MetaPluginProgram::new("file", vec!["-bE", "-"])),
|
||||||
|
MetaPluginType::None => Box::new(MetaPluginNone::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_meta_plugin_type() -> MetaPluginType {
|
||||||
|
let mut default = MetaPluginType::None;
|
||||||
|
for meta_plugin_type in MetaPluginType::iter() {
|
||||||
|
let meta_plugin = get_meta_plugin(meta_plugin_type.clone());
|
||||||
|
if meta_plugin.is_supported() {
|
||||||
|
default = meta_plugin_type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default
|
||||||
|
}
|
||||||
|
|||||||
43
src/meta_plugin/none.rs
Normal file
43
src/meta_plugin/none.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use log::*;
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
||||||
|
pub struct MetaPluginNone {}
|
||||||
|
|
||||||
|
impl MetaPluginNone {
|
||||||
|
pub fn new() -> MetaPluginNone {
|
||||||
|
MetaPluginNone {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetaPlugin for MetaPluginNone {
|
||||||
|
fn create(&self) -> Result<Box<dyn Write>> {
|
||||||
|
Ok(Box::new(DummyWriter::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> io::Result<String> {
|
||||||
|
Ok("none".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _data: &[u8]) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dummy writer that implements Write for the none meta plugin
|
||||||
|
struct DummyWriter;
|
||||||
|
|
||||||
|
impl DummyWriter {
|
||||||
|
fn new() -> Self {
|
||||||
|
DummyWriter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for DummyWriter {
|
||||||
|
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
use crate::meta_plugin::MetaPlugin;
|
||||||
|
use anyhow::{Context, Result, anyhow};
|
||||||
|
use log::*;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MetaPluginProgram {
|
||||||
|
pub program: String,
|
||||||
|
pub args: Vec<String>,
|
||||||
|
pub supported: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetaPluginProgram {
|
||||||
|
pub fn new(program: &str, args: Vec<&str>) -> MetaPluginProgram {
|
||||||
|
let program_path = get_program_path(program);
|
||||||
|
let supported = program_path.is_ok();
|
||||||
|
|
||||||
|
MetaPluginProgram {
|
||||||
|
program: program_path.unwrap_or(program.to_string()),
|
||||||
|
args: args.iter().map(|s| s.to_string()).collect(),
|
||||||
|
supported,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetaPlugin for MetaPluginProgram {
|
||||||
|
fn is_supported(&self) -> bool {
|
||||||
|
self.supported
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self) -> Result<Box<dyn Write>> {
|
||||||
|
debug!("META: Writing using {:?}", *self);
|
||||||
|
|
||||||
|
let program = self.program.clone();
|
||||||
|
let args = self.args.clone();
|
||||||
|
|
||||||
|
debug!("META: Executing command: {:?} {:?}", program, args);
|
||||||
|
|
||||||
|
let mut process = Command::new(program.clone())
|
||||||
|
.args(args.clone())
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.context(anyhow!(
|
||||||
|
"Problem spawning child process: {:?} {:?}",
|
||||||
|
program,
|
||||||
|
args
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(Box::new(ProgramWriter {
|
||||||
|
stdin: process.stdin.take().unwrap(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> io::Result<String> {
|
||||||
|
Ok("program".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _data: &[u8]) {
|
||||||
|
// This is handled by the ProgramWriter implementation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_program_path(program: &str) -> Result<String> {
|
||||||
|
debug!("META: Looking for executable: {}", program);
|
||||||
|
if let Ok(path) = env::var("PATH") {
|
||||||
|
for p in path.split(':') {
|
||||||
|
let p_str = format!("{}/{}", p, program);
|
||||||
|
let stat = fs::metadata(p_str.clone());
|
||||||
|
if let Ok(stat) = stat {
|
||||||
|
let md = stat;
|
||||||
|
let permissions = md.permissions();
|
||||||
|
if md.is_file() && permissions.mode() & 0o111 != 0 {
|
||||||
|
return Ok(p_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(anyhow!("Unable to find binary {} in PATH", program))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user