proc_cli/commands/
kill.rs1use crate::core::{apply_filters, parse_targets, resolve_targets_excluding_self};
12use crate::error::{ProcError, Result};
13use crate::ui::Printer;
14use clap::Args;
15
16#[derive(Args, Debug)]
18pub struct KillCommand {
19 pub target: String,
21
22 #[arg(long, short = 'y')]
24 pub yes: bool,
25
26 #[arg(long)]
28 pub dry_run: bool,
29
30 #[arg(long, short = 'j')]
32 pub json: bool,
33
34 #[arg(long, short = 'v')]
36 pub verbose: bool,
37
38 #[arg(long, short = 'g')]
40 pub graceful: bool,
41
42 #[arg(long = "in", short = 'i', num_args = 0..=1, default_missing_value = ".")]
44 pub in_dir: Option<String>,
45
46 #[arg(long = "by", short = 'b')]
48 pub by_name: Option<String>,
49}
50
51impl KillCommand {
52 pub fn execute(&self) -> Result<()> {
54 let printer = Printer::from_flags(self.json, self.verbose);
55
56 let targets = parse_targets(&self.target);
59 let (mut processes, not_found) = resolve_targets_excluding_self(&targets);
60
61 if !not_found.is_empty() {
63 printer.warning(&format!("Not found: {}", not_found.join(", ")));
64 }
65
66 apply_filters(&mut processes, &self.in_dir, &self.by_name);
68
69 if processes.is_empty() {
70 return Err(ProcError::ProcessNotFound(self.target.clone()));
71 }
72
73 if self.dry_run {
75 printer.print_dry_run("kill", &processes);
76 return Ok(());
77 }
78
79 if !printer.ask_confirm("kill", &processes, self.yes)? {
81 return Ok(());
82 }
83
84 let mut killed = Vec::new();
86 let mut failed = Vec::new();
87
88 for proc in processes {
89 let result = if self.graceful {
90 proc.terminate()
91 } else {
92 proc.kill()
93 };
94
95 match result {
96 Ok(()) => killed.push(proc),
97 Err(e) => failed.push((proc, e.to_string())),
98 }
99 }
100
101 printer.print_kill_result(&killed, &failed);
102
103 if failed.is_empty() {
104 Ok(())
105 } else {
106 Err(ProcError::SignalError(format!(
107 "Failed to kill {} process(es)",
108 failed.len()
109 )))
110 }
111 }
112}