psycho-killer 0.7.1

Interactive process killer, manager and system resources monitor
use anyhow::{anyhow, Context, Ok, Result};
use std::process::{Command, Stdio};

use crate::logs::log;

#[derive(Debug, Clone)]
pub struct MenuAction {
    pub name: &'static str,
    pub operation: Operation,
}

#[derive(Debug, Clone)]
pub enum Operation {
    KillSignal { template: &'static str },
    ShowDetails,
}

pub fn generate_known_menu_actions() -> Vec<MenuAction> {
    vec![
        MenuAction {
            name: "Process details",
            operation: Operation::ShowDetails,
        },
        MenuAction {
            name: "Interrupt: kill -2",
            operation: Operation::KillSignal { template: "kill -2 " },
        },
        MenuAction {
            name: "Terminate gracefully: kill -15",
            operation: Operation::KillSignal { template: "kill -15 " },
        },
        MenuAction {
            name: "Kill forcefully: kill -9",
            operation: Operation::KillSignal { template: "kill -9 " },
        },
        MenuAction {
            name: "Superuser Terminate: sudo kill -15",
            operation: Operation::KillSignal {
                template: "sudo kill -15 ",
            },
        },
        MenuAction {
            name: "Superuser Kill: sudo kill -9",
            operation: Operation::KillSignal {
                template: "sudo kill -9 ",
            },
        },
    ]
}

pub fn kill_pid(pid: &String, command_template: &'static str) -> Result<()> {
    let cmd = format!("{command_template}{pid}");
    execute_shell(cmd)
}

pub fn execute_shell(cmd: String) -> Result<()> {
    log(format!("Executing command: {:?}", cmd).as_str());
    let c = Command::new("sh")
        .arg("-c")
        .arg(cmd.clone())
        .stdin(Stdio::inherit())
        .stderr(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .context("failed to start a command")?;
    let output = c.wait_with_output().context("failed to read command output")?;

    if !output.status.success() {
        let error = format!(
            "Failed to execute command: {:?}, {}\n{}\n{}",
            cmd,
            output.status,
            String::from_utf8_lossy(&output.stderr),
            String::from_utf8_lossy(&output.stdout),
        );
        log(error.as_str());
        return Err(anyhow!(error));
    }
    Ok(())
}