set envvars

This commit is contained in:
Jana Dönszelmann 2026-02-20 12:40:07 +01:00
commit 3963fc50c3
No known key found for this signature in database
9 changed files with 3248 additions and 0 deletions

163
src/tui/reader.rs Normal file
View file

@ -0,0 +1,163 @@
use std::{
fs::File,
io::{self, BufRead, BufReader},
mem,
path::{Path, PathBuf},
rc::Rc,
sync::OnceLock,
};
use crate::tui::{
filter::{Filter, FilterKind},
model::{LogEntry, RawLogEntry},
};
pub struct LogfileReader {
pub path: PathBuf,
file: BufReader<File>,
entries: Vec<Rc<LogEntry>>,
filters: Vec<Rc<Filter>>,
}
impl LogfileReader {
pub fn new(p: &Path) -> io::Result<Self> {
Ok(Self {
file: BufReader::new(File::open(p)?),
path: p.to_path_buf(),
entries: Vec::new(),
filters: Vec::new(),
})
}
pub fn add_filter(&mut self, filter: Filter) {
self.filters.push(Rc::new(filter));
}
fn next_line(&mut self) -> Option<String> {
let mut res = String::new();
match self.file.read_line(&mut res) {
Err(e) => {
eprintln!("error: {e:?}");
None
}
Ok(0) => None,
Ok(_) => Some(res),
}
}
fn next_raw_entry(&mut self) -> Option<RawLogEntry> {
let line = self.next_line()?;
match serde_json::from_str(&line) {
Ok(i) => Some(i),
Err(e) => {
eprintln!("deserializing: {e:?} in {line}");
None
}
}
}
fn next_entry(&mut self) -> Option<Rc<LogEntry>> {
let mut stack = Vec::<(RawLogEntry, Vec<Rc<LogEntry>>)>::new();
let mut curr = Vec::<Rc<LogEntry>>::new();
loop {
let entry = self.next_raw_entry()?;
let new_entry = Rc::new(match entry.fields.message() {
Some("enter") => {
stack.push((entry, mem::take(&mut curr)));
continue;
}
Some("exit") => {
// TODO: does it match?
let Some((enter, prev)) = stack.pop() else {
panic!("exit before entry");
};
let sub_entries = mem::replace(&mut curr, prev);
LogEntry::Sub {
enter: enter,
sub_entries,
exit: entry,
count_sub: OnceLock::new(),
}
}
_ => LogEntry::Single { raw: entry },
});
if stack.is_empty() {
return Some(new_entry);
} else {
curr.push(new_entry);
}
}
}
pub fn iter_from(&mut self, start: usize) -> FilterAdapter<EntryIterator<'_>> {
FilterAdapter {
filters: self.filters.clone(),
inner: EntryIterator {
curr: start,
reader: self,
},
}
}
fn add_next_entry(&mut self) -> Option<()> {
let entry = self.next_entry()?;
self.entries.push(entry);
Some(())
}
}
pub struct EntryIterator<'a> {
curr: usize,
reader: &'a mut LogfileReader,
}
impl<'a> Iterator for EntryIterator<'a> {
type Item = Rc<LogEntry>;
fn next(&mut self) -> Option<Self::Item> {
while self.reader.entries.len() <= self.curr {
self.reader.add_next_entry()?;
}
let res = Rc::clone(&self.reader.entries[self.curr]);
self.curr += 1;
Some(res)
}
}
pub struct FilterAdapter<I> {
filters: Vec<Rc<Filter>>,
inner: I,
}
impl<I: IntoIterator> FilterAdapter<I> {
pub fn new(file: &LogfileReader, inner: I) -> FilterAdapter<I::IntoIter> {
Self {
filters: file.filters.clone(),
inner: inner.into_iter(),
}
}
}
impl<I: Iterator> Iterator for FilterAdapter<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
'next_entry: loop {
let res = self.inner.next()?;
for filter in &self.reader.filters {
if let FilterKind::Remove = filter.kind
&& filter.matcher.matches(&res)
{
continue 'next_entry;
}
}
break Some(res);
}
}
}