proc_cli/commands/
thaw.rs1#[cfg(unix)]
10use crate::core::{parse_targets, resolve_in_dir, resolve_targets_excluding_self};
11use crate::error::{ProcError, Result};
12#[cfg(unix)]
13use crate::ui::{OutputFormat, Printer};
14use clap::Args;
15#[cfg(unix)]
16use dialoguer::Confirm;
17#[cfg(unix)]
18use std::path::PathBuf;
19
20#[derive(Args, Debug)]
22pub struct ThawCommand {
23 #[arg(required = true)]
25 pub target: String,
26
27 #[arg(long, short = 'y')]
29 pub yes: bool,
30
31 #[arg(long)]
33 pub dry_run: bool,
34
35 #[arg(long, short = 'j')]
37 pub json: bool,
38
39 #[arg(long, short = 'v')]
41 pub verbose: bool,
42
43 #[arg(long = "in", short = 'i', num_args = 0..=1, default_missing_value = ".")]
45 pub in_dir: Option<String>,
46
47 #[arg(long = "by", short = 'b')]
49 pub by_name: Option<String>,
50}
51
52impl ThawCommand {
53 #[cfg(unix)]
55 pub fn execute(&self) -> Result<()> {
56 use nix::sys::signal::Signal;
57
58 let format = if self.json {
59 OutputFormat::Json
60 } else {
61 OutputFormat::Human
62 };
63 let printer = Printer::new(format, self.verbose);
64
65 let targets = parse_targets(&self.target);
66 let (mut processes, not_found) = resolve_targets_excluding_self(&targets);
67
68 if !not_found.is_empty() {
69 printer.warning(&format!("Not found: {}", not_found.join(", ")));
70 }
71
72 let in_dir_filter = resolve_in_dir(&self.in_dir);
74 processes.retain(|p| {
75 if let Some(ref dir_path) = in_dir_filter {
76 if let Some(ref cwd) = p.cwd {
77 if !PathBuf::from(cwd).starts_with(dir_path) {
78 return false;
79 }
80 } else {
81 return false;
82 }
83 }
84 if let Some(ref name) = self.by_name {
85 if !p.name.to_lowercase().contains(&name.to_lowercase()) {
86 return false;
87 }
88 }
89 true
90 });
91
92 if processes.is_empty() {
93 return Err(ProcError::ProcessNotFound(self.target.clone()));
94 }
95
96 if self.dry_run {
97 printer.print_processes(&processes);
98 printer.warning(&format!(
99 "Dry run: would resume {} process{}",
100 processes.len(),
101 if processes.len() == 1 { "" } else { "es" }
102 ));
103 return Ok(());
104 }
105
106 if !self.yes && !self.json {
107 printer.print_confirmation("resume", &processes);
108
109 let prompt = format!(
110 "Resume {} process{}?",
111 processes.len(),
112 if processes.len() == 1 { "" } else { "es" }
113 );
114
115 if !Confirm::new()
116 .with_prompt(prompt)
117 .default(false)
118 .interact()?
119 {
120 printer.warning("Aborted");
121 return Ok(());
122 }
123 }
124
125 let mut succeeded = Vec::new();
126 let mut failed = Vec::new();
127
128 for proc in &processes {
129 match proc.send_signal(Signal::SIGCONT) {
130 Ok(()) => succeeded.push(proc.clone()),
131 Err(e) => failed.push((proc.clone(), e.to_string())),
132 }
133 }
134
135 printer.print_action_result("Resumed", &succeeded, &failed);
136
137 Ok(())
138 }
139
140 #[cfg(not(unix))]
142 pub fn execute(&self) -> Result<()> {
143 Err(ProcError::NotSupported(
144 "thaw (SIGCONT) is not supported on Windows".to_string(),
145 ))
146 }
147}