fuckport 0.1.6

A CLI for killing processes by PID, name, or port.
Documentation
use std::backtrace::BacktraceStatus;

use clap::Parser;

use fuckport::cli::Cli;
use fuckport::error::AppResult;
use fuckport::input::parse_targets;
use fuckport::interactive::pick_interactive;
use fuckport::killer::{KillOptions, kill_processes};
use fuckport::process::ProcessCatalog;

fn main() {
    let cli = Cli::parse();

    if let Err(error) = run(cli) {
        report_error(&error);
        std::process::exit(1);
    }
}

fn run(cli: Cli) -> AppResult<()> {
    let mut catalog = ProcessCatalog::load()?;
    let interactive_mode = cli.interactive || cli.targets.is_empty();

    let selected_pids = if interactive_mode {
        pick_interactive(&catalog, cli.verbose)?
    } else {
        let targets = parse_targets(&cli.targets);
        catalog.resolve_targets(&targets, cli.case_sensitive)?
    };

    if interactive_mode && selected_pids.is_empty() {
        return Ok(());
    }

    let options = KillOptions {
        force: cli.force,
        silent: cli.silent,
        force_after_timeout: cli.force_after_timeout,
        wait_for_exit: cli.wait_for_exit,
    };

    kill_processes(&mut catalog, &selected_pids, &options)
}

fn report_error(error: &anyhow::Error) {
    eprintln!("Error: {error}");

    for cause in error.chain().skip(1) {
        eprintln!("Caused by: {cause}");
    }

    let backtrace = error.backtrace();
    if matches!(
        backtrace.status(),
        BacktraceStatus::Captured | BacktraceStatus::Disabled
    ) {
        if backtrace.status() == BacktraceStatus::Captured {
            eprintln!("\nBacktrace:\n{backtrace}");
        }
    }
}