Ugh
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use super::{FilterPlugin, FilterOption};
|
||||
use std::io::{Result, Read, Write, BufRead};
|
||||
use super::{FilterOption, FilterPlugin};
|
||||
use regex::Regex;
|
||||
use std::io::{BufRead, Read, Result, Write};
|
||||
|
||||
/// A filter that matches lines against a regular expression pattern.
|
||||
///
|
||||
@@ -40,9 +40,7 @@ impl GrepFilter {
|
||||
pub fn new(pattern: String) -> Result<Self> {
|
||||
let regex = Regex::new(&pattern)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
|
||||
Ok(Self {
|
||||
regex,
|
||||
})
|
||||
Ok(Self { regex })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +97,7 @@ impl FilterPlugin for GrepFilter {
|
||||
regex: self.regex.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter.
|
||||
///
|
||||
/// The only option is the required "pattern" for the regex.
|
||||
@@ -116,12 +114,10 @@ impl FilterPlugin for GrepFilter {
|
||||
/// assert!(opts[0].required);
|
||||
/// ```
|
||||
fn options(&self) -> Vec<FilterOption> {
|
||||
vec![
|
||||
FilterOption {
|
||||
name: "pattern".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
vec![FilterOption {
|
||||
name: "pattern".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{FilterPlugin, FilterOption};
|
||||
use std::io::{Result, Read, Write, BufRead};
|
||||
use super::{FilterOption, FilterPlugin};
|
||||
use crate::common::PIPESIZE;
|
||||
use crate::services::filter_service::register_filter_plugin;
|
||||
use std::io::{BufRead, Read, Result, Write};
|
||||
|
||||
/// A filter that reads the first N bytes from the input stream.
|
||||
///
|
||||
@@ -41,9 +41,7 @@ impl HeadBytesFilter {
|
||||
/// assert_eq!(filter.remaining, 1024);
|
||||
/// ```
|
||||
pub fn new(count: usize) -> Self {
|
||||
Self {
|
||||
remaining: count,
|
||||
}
|
||||
Self { remaining: count }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +74,7 @@ impl FilterPlugin for HeadBytesFilter {
|
||||
if self.remaining == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
let mut buffer = vec![0; PIPESIZE];
|
||||
while self.remaining > 0 {
|
||||
let to_read = std::cmp::min(self.remaining, PIPESIZE);
|
||||
@@ -102,7 +100,7 @@ impl FilterPlugin for HeadBytesFilter {
|
||||
remaining: self.remaining,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter.
|
||||
///
|
||||
/// Defines the "count" parameter as required with no default.
|
||||
@@ -111,13 +109,11 @@ impl FilterPlugin for HeadBytesFilter {
|
||||
///
|
||||
/// Vector of `FilterOption` describing parameters.
|
||||
fn options(&self) -> Vec<FilterOption> {
|
||||
vec![
|
||||
FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
vec![FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,42 +148,39 @@ impl HeadLinesFilter {
|
||||
/// assert_eq!(filter.remaining, 3);
|
||||
/// ```
|
||||
pub fn new(count: usize) -> Self {
|
||||
Self {
|
||||
remaining: count,
|
||||
}
|
||||
Self { remaining: count }
|
||||
}
|
||||
}
|
||||
|
||||
/// Filters input by reading only the first N lines and writing them to the output.
|
||||
///
|
||||
///
|
||||
/// Uses buffered line reading to process input line-by-line until the limit or EOF.
|
||||
///
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
///
|
||||
/// * `reader` - Mutable reference to the input data stream.
|
||||
/// * `writer` - Mutable reference to the output stream.
|
||||
///
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
///
|
||||
/// * `Result<()>` - Success if filtering completes, or I/O error.
|
||||
///
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
///
|
||||
/// * `io::Error` from line reading or writing operations.
|
||||
///
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// // Assuming a filter chain with head_lines(2)
|
||||
/// // Input: "Line1\nLine2\nLine3" becomes "Line1\nLine2\n"
|
||||
/// ```
|
||||
|
||||
impl FilterPlugin for HeadLinesFilter {
|
||||
fn filter(&mut self, reader: &mut dyn Read, writer: &mut dyn Write) -> Result<()> {
|
||||
if self.remaining == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
let mut buf_reader = std::io::BufReader::new(reader);
|
||||
for line in buf_reader.by_ref().lines() {
|
||||
let line = line?;
|
||||
@@ -201,33 +194,31 @@ impl FilterPlugin for HeadLinesFilter {
|
||||
}
|
||||
|
||||
/// Clones this filter into a new boxed instance.
|
||||
///
|
||||
///
|
||||
/// Creates an independent copy with the same configuration.
|
||||
///
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
///
|
||||
/// A new `Box<dyn FilterPlugin>` clone.
|
||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||
Box::new(Self {
|
||||
remaining: self.remaining,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter.
|
||||
///
|
||||
///
|
||||
/// Defines the "count" parameter as required with no default.
|
||||
///
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
///
|
||||
/// Vector of `FilterOption` describing parameters.
|
||||
fn options(&self) -> Vec<FilterOption> {
|
||||
vec![
|
||||
FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
vec![FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::io::{Result, Read, Write};
|
||||
use std::io::{Read, Result, Write};
|
||||
use std::str::FromStr;
|
||||
use strum::EnumString;
|
||||
|
||||
pub mod grep;
|
||||
/// Filter plugin module for processing input streams.
|
||||
///
|
||||
/// This module defines the `FilterPlugin` trait and `FilterChain` for chaining filters,
|
||||
@@ -17,19 +18,18 @@ use strum::EnumString;
|
||||
/// chain.filter(&mut reader, &mut writer)?;
|
||||
/// ```
|
||||
pub mod head;
|
||||
pub mod tail;
|
||||
pub mod skip;
|
||||
pub mod grep;
|
||||
pub mod strip_ansi;
|
||||
pub mod tail;
|
||||
pub mod utils;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use head::{HeadBytesFilter, HeadLinesFilter};
|
||||
pub use tail::{TailBytesFilter, TailLinesFilter};
|
||||
pub use skip::{SkipBytesFilter, SkipLinesFilter};
|
||||
pub use grep::GrepFilter;
|
||||
pub use head::{HeadBytesFilter, HeadLinesFilter};
|
||||
pub use skip::{SkipBytesFilter, SkipLinesFilter};
|
||||
pub use strip_ansi::StripAnsiFilter;
|
||||
pub use tail::{TailBytesFilter, TailLinesFilter};
|
||||
|
||||
/// Represents an option for a filter plugin.
|
||||
///
|
||||
@@ -195,7 +195,6 @@ pub struct FilterChain {
|
||||
/// chain.add_plugin(Box::new(HeadLinesFilter::new(10)));
|
||||
/// chain.filter(&mut reader, &mut writer)?;
|
||||
/// ```
|
||||
|
||||
impl Clone for FilterChain {
|
||||
/// Clones this filter chain.
|
||||
///
|
||||
@@ -222,6 +221,12 @@ impl Clone for Box<dyn FilterPlugin> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FilterChain {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterChain {
|
||||
/// Creates a new empty filter chain.
|
||||
///
|
||||
@@ -286,19 +291,19 @@ impl FilterChain {
|
||||
std::io::copy(reader, writer)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
// For multiple plugins, we need to chain them together
|
||||
// We'll use a temporary buffer to hold intermediate results
|
||||
let mut current_data = Vec::new();
|
||||
std::io::copy(reader, &mut current_data)?;
|
||||
|
||||
|
||||
// Store the plugins length to avoid borrowing issues
|
||||
let plugins_len = self.plugins.len();
|
||||
|
||||
|
||||
for i in 0..plugins_len {
|
||||
// Create a cursor for the current data
|
||||
let mut input = std::io::Cursor::new(std::mem::take(&mut current_data));
|
||||
|
||||
|
||||
// For the last plugin, write directly to the output writer
|
||||
if i == plugins_len - 1 {
|
||||
self.plugins[i].filter(&mut input, writer)?;
|
||||
@@ -337,14 +342,14 @@ pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
|
||||
// Parse parameters
|
||||
let mut options = HashMap::new();
|
||||
let mut unnamed_params = Vec::new();
|
||||
|
||||
|
||||
// Split parameters by commas
|
||||
for param in params.split(',') {
|
||||
let param = param.trim();
|
||||
if param.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if it's a named parameter (key=value)
|
||||
if let Some((key, value)) = param.split_once('=') {
|
||||
let key = key.trim();
|
||||
@@ -356,10 +361,11 @@ pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
|
||||
unnamed_params.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create the appropriate filter plugin
|
||||
if let Ok(filter_type) = FilterType::from_str(filter_name) {
|
||||
let plugin = create_filter_with_options(filter_type, &unnamed_params, &options)?;
|
||||
let plugin =
|
||||
create_filter_with_options(filter_type, &unnamed_params, &options)?;
|
||||
chain.add_plugin(plugin);
|
||||
continue;
|
||||
}
|
||||
@@ -375,7 +381,7 @@ pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
|
||||
_ => {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("Filter '{}' requires parameters", part)
|
||||
format!("Filter '{}' requires parameters", part),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -385,7 +391,7 @@ pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
|
||||
// If we get here, the filter wasn't recognized
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("Unknown filter: {}", part)
|
||||
format!("Unknown filter: {}", part),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -420,17 +426,20 @@ fn create_filter_with_options(
|
||||
FilterType::SkipLines => skip::SkipLinesFilter::new(0).options(),
|
||||
FilterType::StripAnsi => strip_ansi::StripAnsiFilter::new().options(),
|
||||
};
|
||||
|
||||
|
||||
let mut options = HashMap::new();
|
||||
|
||||
|
||||
// Process unnamed parameters
|
||||
if unnamed_params.len() > option_defs.len() {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("Too many unnamed parameters (expected at most {})", option_defs.len())
|
||||
format!(
|
||||
"Too many unnamed parameters (expected at most {})",
|
||||
option_defs.len()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
for (i, param) in unnamed_params.iter().enumerate() {
|
||||
if i >= option_defs.len() {
|
||||
break;
|
||||
@@ -438,19 +447,19 @@ fn create_filter_with_options(
|
||||
let option_name = &option_defs[i].name;
|
||||
options.insert(option_name.clone(), param.clone());
|
||||
}
|
||||
|
||||
|
||||
// Process named options
|
||||
for (key, value) in named_options {
|
||||
// Check if the option exists
|
||||
if !option_defs.iter().any(|opt| &opt.name == key) {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("Unknown option '{}'", key)
|
||||
format!("Unknown option '{}'", key),
|
||||
));
|
||||
}
|
||||
options.insert(key.clone(), value.clone());
|
||||
}
|
||||
|
||||
|
||||
// Fill in defaults and check required options
|
||||
for opt_def in option_defs {
|
||||
if !options.contains_key(&opt_def.name) {
|
||||
@@ -459,12 +468,12 @@ fn create_filter_with_options(
|
||||
} else if opt_def.required {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("Missing required option '{}'", opt_def.name)
|
||||
format!("Missing required option '{}'", opt_def.name),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create the specific filter with the processed options
|
||||
create_specific_filter(filter_type, &options)
|
||||
}
|
||||
@@ -485,72 +494,93 @@ fn create_specific_filter(
|
||||
) -> Result<Box<dyn FilterPlugin>> {
|
||||
match filter_type {
|
||||
FilterType::Grep => {
|
||||
let pattern = options.get("pattern")
|
||||
let pattern = options
|
||||
.get("pattern")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"grep filter requires 'pattern' parameter"
|
||||
))?;
|
||||
.ok_or_else(|| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"grep filter requires 'pattern' parameter",
|
||||
)
|
||||
})?;
|
||||
grep::GrepFilter::new(pattern.to_string()).map(|f| Box::new(f) as Box<dyn FilterPlugin>)
|
||||
}
|
||||
FilterType::HeadBytes => {
|
||||
let count = options.get("count")
|
||||
let count = options
|
||||
.get("count")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|n| n as usize)
|
||||
.ok_or_else(|| std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"head_bytes filter requires 'count' parameter"
|
||||
))?;
|
||||
.ok_or_else(|| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"head_bytes filter requires 'count' parameter",
|
||||
)
|
||||
})?;
|
||||
Ok(Box::new(head::HeadBytesFilter::new(count)))
|
||||
}
|
||||
FilterType::HeadLines => {
|
||||
let count = options.get("count")
|
||||
let count = options
|
||||
.get("count")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|n| n as usize)
|
||||
.ok_or_else(|| std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"head_lines filter requires 'count' parameter"
|
||||
))?;
|
||||
.ok_or_else(|| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"head_lines filter requires 'count' parameter",
|
||||
)
|
||||
})?;
|
||||
Ok(Box::new(head::HeadLinesFilter::new(count)))
|
||||
}
|
||||
FilterType::TailBytes => {
|
||||
let count = options.get("count")
|
||||
let count = options
|
||||
.get("count")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|n| n as usize)
|
||||
.ok_or_else(|| std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"tail_bytes filter requires 'count' parameter"
|
||||
))?;
|
||||
.ok_or_else(|| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"tail_bytes filter requires 'count' parameter",
|
||||
)
|
||||
})?;
|
||||
Ok(Box::new(tail::TailBytesFilter::new(count)))
|
||||
}
|
||||
FilterType::TailLines => {
|
||||
let count = options.get("count")
|
||||
let count = options
|
||||
.get("count")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|n| n as usize)
|
||||
.ok_or_else(|| std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"tail_lines filter requires 'count' parameter"
|
||||
))?;
|
||||
.ok_or_else(|| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"tail_lines filter requires 'count' parameter",
|
||||
)
|
||||
})?;
|
||||
Ok(Box::new(tail::TailLinesFilter::new(count)))
|
||||
}
|
||||
FilterType::SkipBytes => {
|
||||
let count = options.get("count")
|
||||
let count = options
|
||||
.get("count")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|n| n as usize)
|
||||
.ok_or_else(|| std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"skip_bytes filter requires 'count' parameter"
|
||||
))?;
|
||||
.ok_or_else(|| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"skip_bytes filter requires 'count' parameter",
|
||||
)
|
||||
})?;
|
||||
Ok(Box::new(skip::SkipBytesFilter::new(count)))
|
||||
}
|
||||
FilterType::SkipLines => {
|
||||
let count = options.get("count")
|
||||
let count = options
|
||||
.get("count")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|n| n as usize)
|
||||
.ok_or_else(|| std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"skip_lines filter requires 'count' parameter"
|
||||
))?;
|
||||
.ok_or_else(|| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"skip_lines filter requires 'count' parameter",
|
||||
)
|
||||
})?;
|
||||
Ok(Box::new(skip::SkipLinesFilter::new(count)))
|
||||
}
|
||||
FilterType::StripAnsi => {
|
||||
@@ -558,7 +588,7 @@ fn create_specific_filter(
|
||||
if !options.is_empty() {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"strip_ansi filter doesn't take parameters"
|
||||
"strip_ansi filter doesn't take parameters",
|
||||
));
|
||||
}
|
||||
Ok(Box::new(strip_ansi::StripAnsiFilter::new()))
|
||||
@@ -578,17 +608,17 @@ fn create_specific_filter(
|
||||
fn parse_option_value(input: &str) -> Result<serde_json::Value> {
|
||||
// Remove quotes if present
|
||||
let input = input.trim_matches(|c| c == '\'' || c == '"');
|
||||
|
||||
|
||||
// Try to parse as number
|
||||
if let Ok(num) = input.parse::<i64>() {
|
||||
return Ok(serde_json::Value::Number(num.into()));
|
||||
}
|
||||
if let Ok(num) = input.parse::<f64>() {
|
||||
if let Some(number) = serde_json::Number::from_f64(num) {
|
||||
return Ok(serde_json::Value::Number(number));
|
||||
}
|
||||
if let Ok(num) = input.parse::<f64>()
|
||||
&& let Some(number) = serde_json::Number::from_f64(num)
|
||||
{
|
||||
return Ok(serde_json::Value::Number(number));
|
||||
}
|
||||
|
||||
|
||||
// Try to parse as boolean
|
||||
if input.eq_ignore_ascii_case("true") {
|
||||
return Ok(serde_json::Value::Bool(true));
|
||||
@@ -596,7 +626,7 @@ fn parse_option_value(input: &str) -> Result<serde_json::Value> {
|
||||
if input.eq_ignore_ascii_case("false") {
|
||||
return Ok(serde_json::Value::Bool(false));
|
||||
}
|
||||
|
||||
|
||||
// Treat as string
|
||||
Ok(serde_json::Value::String(input.to_string()))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{FilterPlugin, FilterOption};
|
||||
use std::io::{Result, Read, Write, BufRead};
|
||||
use super::{FilterOption, FilterPlugin};
|
||||
use crate::common::PIPESIZE;
|
||||
use crate::services::filter_service::register_filter_plugin;
|
||||
use std::io::{BufRead, Read, Result, Write};
|
||||
|
||||
/// A filter that skips the first N bytes from the input stream.
|
||||
pub struct SkipBytesFilter {
|
||||
@@ -15,9 +15,7 @@ impl SkipBytesFilter {
|
||||
///
|
||||
/// * `count` - The number of bytes to skip from the beginning of the input.
|
||||
pub fn new(count: usize) -> Self {
|
||||
Self {
|
||||
remaining: count,
|
||||
}
|
||||
Self { remaining: count }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +43,7 @@ impl FilterPlugin for SkipBytesFilter {
|
||||
self.remaining -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copy the remaining data using io::copy for efficiency
|
||||
std::io::copy(reader, writer)?;
|
||||
Ok(())
|
||||
@@ -61,20 +59,18 @@ impl FilterPlugin for SkipBytesFilter {
|
||||
remaining: self.remaining,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `FilterOption` describing the filter's configurable parameters.
|
||||
fn options(&self) -> Vec<FilterOption> {
|
||||
vec![
|
||||
FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
vec![FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +86,7 @@ impl SkipLinesFilter {
|
||||
///
|
||||
/// * `count` - The number of lines to skip from the beginning of the input.
|
||||
pub fn new(count: usize) -> Self {
|
||||
Self {
|
||||
remaining: count,
|
||||
}
|
||||
Self { remaining: count }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,20 +124,18 @@ impl FilterPlugin for SkipLinesFilter {
|
||||
remaining: self.remaining,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `FilterOption` describing the filter's configurable parameters.
|
||||
fn options(&self) -> Vec<FilterOption> {
|
||||
vec![
|
||||
FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
vec![FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::io::{Result, Read, Write};
|
||||
use super::{FilterOption, FilterPlugin};
|
||||
use std::io::{Read, Result, Write};
|
||||
use strip_ansi_escapes::Writer;
|
||||
use super::{FilterPlugin, FilterOption};
|
||||
|
||||
/// A filter that removes ANSI escape sequences from the input.
|
||||
///
|
||||
@@ -47,7 +47,7 @@ impl FilterPlugin for StripAnsiFilter {
|
||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||
Box::new(Self)
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter (none required).
|
||||
///
|
||||
/// # Returns
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::{FilterPlugin, FilterOption};
|
||||
use std::io::{Result, Read, Write, BufRead};
|
||||
use std::collections::VecDeque;
|
||||
use super::{FilterOption, FilterPlugin};
|
||||
use crate::common::PIPESIZE;
|
||||
use crate::services::filter_service::register_filter_plugin;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{BufRead, Read, Result, Write};
|
||||
|
||||
/// A filter that reads the last N bytes from the input stream.
|
||||
pub struct TailBytesFilter {
|
||||
@@ -42,7 +42,7 @@ impl FilterPlugin for TailBytesFilter {
|
||||
if bytes_read == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Add new data to the buffer
|
||||
for &byte in &temp_buffer[..bytes_read] {
|
||||
if self.buffer.len() == self.count {
|
||||
@@ -51,7 +51,7 @@ impl FilterPlugin for TailBytesFilter {
|
||||
self.buffer.push_back(byte);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the buffered data at the end
|
||||
let result: Vec<u8> = self.buffer.iter().cloned().collect();
|
||||
writer.write_all(&result)?;
|
||||
@@ -69,20 +69,18 @@ impl FilterPlugin for TailBytesFilter {
|
||||
count: self.count,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `FilterOption` describing the filter's configurable parameters.
|
||||
fn options(&self) -> Vec<FilterOption> {
|
||||
vec![
|
||||
FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
vec![FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +124,7 @@ impl FilterPlugin for TailLinesFilter {
|
||||
}
|
||||
self.lines.push_back(line);
|
||||
}
|
||||
|
||||
|
||||
// Write the buffered lines
|
||||
for line in &self.lines {
|
||||
writeln!(writer, "{}", line)?;
|
||||
@@ -145,20 +143,18 @@ impl FilterPlugin for TailLinesFilter {
|
||||
count: self.count,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Returns the configuration options for this filter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `FilterOption` describing the filter's configurable parameters.
|
||||
fn options(&self) -> Vec<FilterOption> {
|
||||
vec![
|
||||
FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
vec![FilterOption {
|
||||
name: "count".to_string(),
|
||||
default: None,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user