refactor: rename meta to plugin in table header
This commit is contained in:
committed by
Andrew Phillips (aider)
parent
7bc9dedccd
commit
10cd22ee1a
224
src/meta_plugin/command.rs
Normal file
224
src/meta_plugin/command.rs
Normal file
@@ -0,0 +1,224 @@
|
||||
use log::*;
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio, Child};
|
||||
use which::which;
|
||||
|
||||
use crate::meta_plugin::{MetaPlugin, MetaPluginResponse};
|
||||
|
||||
pub struct MetaPluginCommand {
|
||||
pub program: String,
|
||||
pub args: Vec<String>,
|
||||
pub supported: bool,
|
||||
pub meta_name: String,
|
||||
pub split_whitespace: bool,
|
||||
process: Option<Child>,
|
||||
writer: Option<Box<dyn Write>>,
|
||||
result: Option<String>,
|
||||
outputs: std::collections::HashMap<String, serde_yaml::Value>,
|
||||
options: std::collections::HashMap<String, serde_yaml::Value>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for MetaPluginCommand {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("MetaPluginCommand")
|
||||
.field("program", &self.program)
|
||||
.field("args", &self.args)
|
||||
.field("supported", &self.supported)
|
||||
.field("meta_name", &self.meta_name)
|
||||
.field("split_whitespace", &self.split_whitespace)
|
||||
.field("process", &self.process)
|
||||
.field("writer", &"Box<dyn Write>")
|
||||
.field("outputs", &self.outputs)
|
||||
.field("options", &self.options)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl MetaPluginCommand {
|
||||
pub fn new(
|
||||
program: &str,
|
||||
args: Vec<&str>,
|
||||
meta_name: String,
|
||||
split_whitespace: bool,
|
||||
_options: Option<std::collections::HashMap<String, serde_yaml::Value>>,
|
||||
outputs: Option<std::collections::HashMap<String, serde_yaml::Value>>,
|
||||
) -> MetaPluginCommand {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
MetaPluginCommand {
|
||||
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,
|
||||
meta_name,
|
||||
split_whitespace,
|
||||
process: None,
|
||||
writer: None,
|
||||
result: None,
|
||||
outputs: final_outputs,
|
||||
options: final_options,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl MetaPlugin for MetaPluginCommand {
|
||||
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());
|
||||
|
||||
// Create metadata to be returned
|
||||
metadata.push(crate::meta_plugin::MetaData {
|
||||
name: self.meta_name.clone(),
|
||||
value: result,
|
||||
});
|
||||
}
|
||||
} 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_name(&self) -> String {
|
||||
self.meta_name.clone()
|
||||
}
|
||||
|
||||
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<String, serde_yaml::Value> {
|
||||
&self.outputs
|
||||
}
|
||||
|
||||
fn outputs_mut(&mut self) -> &mut std::collections::HashMap<String, serde_yaml::Value> {
|
||||
&mut self.outputs
|
||||
}
|
||||
|
||||
fn default_outputs(&self) -> Vec<String> {
|
||||
vec![self.meta_name.clone()]
|
||||
}
|
||||
|
||||
|
||||
fn options(&self) -> &std::collections::HashMap<String, serde_yaml::Value> {
|
||||
&self.options
|
||||
}
|
||||
|
||||
fn options_mut(&mut self) -> &mut std::collections::HashMap<String, serde_yaml::Value> {
|
||||
&mut self.options
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user