pidcat 0.2.1

An adb logcat wrapper and filters
Documentation
use crate::cli::Cli;
use crate::filter::{BufferFilter, Filter, LevelFilter, PidFilter, RevertFilter, TagFilter};
use crate::sink::{FileSink, Sink, TerminalSink};
use crate::source::{ADBSource, Source};
use anyhow::Result;
use futures::StreamExt;
use tokio::process::{Child, Command};

mod cli;
mod filter;
mod log;
mod sink;
mod source;

async fn run() -> Result<()> {
    let cli = cli::cli()?;
    let _ = which::which("adb")?;

    tokio::spawn(async move {
        if cli.clear {
            spawn_adb_logcat_clear().await;
        } else {
            fetch(cli).await;
        }
    })
    .await?;

    Ok(())
}

#[tokio::main]
async fn main() {
    match run().await {
        Ok(_) => {}
        Err(_) => {}
    }
}

async fn fetch(cli: Cli) {
    let source = ADBSource::new(if cli.device.is_empty() {
        None
    } else {
        Some(cli.device)
    });

    let filters: Vec<Box<dyn Filter>> = vec![
        Box::new(PidFilter::new(cli.process)),
        Box::new(BufferFilter::new(cli.buffers)),
        Box::new(LevelFilter::new(cli.level)),
        Box::new(TagFilter::new(cli.tag, cli.ignore)),
        Box::new(RevertFilter::new(cli.revert, cli.ignore)),
    ];

    let mut sinks: Vec<Box<dyn Sink>> = Vec::new();

    sinks.push(Box::new(TerminalSink::new(cli.color, cli.tag_width)));
    if let Some(file) = cli.output {
        if let Ok(file) = FileSink::new(file).await {
            sinks.push(Box::new(file));
        }
    }

    let mut logs = source.source().await;

    while let Some(r) = logs.next().await {
        match r {
            Ok(log) => {
                let mut is_filter = false;
                for filter in &filters {
                    if filter.filter(&log).await {
                        is_filter = true;
                        break;
                    }
                }

                if !is_filter {
                    for sink in &sinks {
                        sink.write(log.clone()).await;
                    }
                }
            }
            Err(_) => {}
        }
    }
}

async fn spawn_adb_logcat_clear() -> Child {
    let mut command = Command::new("adb");
    command.stdout(std::process::Stdio::piped());
    command.arg("logcat");
    command.arg("-c");
    command.spawn().expect("Failed to execute adb logcat -c")
}