use crate::common::ProgramWriter; 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}; use crate::meta_plugin::MetaPlugin; #[derive(Clone, Debug)] pub struct MetaPluginProgram { pub program: String, pub args: Vec, 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> { 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 { Ok("program".to_string()) } fn update(&mut self, _data: &[u8]) { // This is handled by the ProgramWriter implementation } } fn get_program_path(program: &str) -> Result { 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)) }