Skip to main content

proc_cli/commands/
thaw.rs

1//! `proc thaw` - Resume frozen processes with SIGCONT
2//!
3//! Examples:
4//!   proc thaw node              # Resume all frozen node processes
5//!   proc thaw :3000             # Resume process on port 3000
6//!   proc thaw :3000,:8080       # Resume multiple targets
7//!   proc thaw node --yes        # Skip confirmation
8
9#[cfg(unix)]
10use crate::core::{apply_filters, parse_targets, resolve_targets_excluding_self};
11use crate::error::{ProcError, Result};
12#[cfg(unix)]
13use crate::ui::Printer;
14use clap::Args;
15
16/// Resume frozen process(es) with SIGCONT
17#[derive(Args, Debug)]
18pub struct ThawCommand {
19    /// Target(s): process name, PID, or :port (comma-separated for multiple)
20    #[arg(required = true)]
21    pub target: String,
22
23    /// Skip confirmation prompt
24    #[arg(long, short = 'y')]
25    pub yes: bool,
26
27    /// Show what would be resumed without actually resuming
28    #[arg(long)]
29    pub dry_run: bool,
30
31    /// Output as JSON
32    #[arg(long, short = 'j')]
33    pub json: bool,
34
35    /// Show verbose output
36    #[arg(long, short = 'v')]
37    pub verbose: bool,
38
39    /// Filter by directory (defaults to current directory if no path given)
40    #[arg(long = "in", short = 'i', num_args = 0..=1, default_missing_value = ".")]
41    pub in_dir: Option<String>,
42
43    /// Filter by process name
44    #[arg(long = "by", short = 'b')]
45    pub by_name: Option<String>,
46}
47
48impl ThawCommand {
49    /// Executes the thaw command, resuming frozen processes with SIGCONT.
50    #[cfg(unix)]
51    pub fn execute(&self) -> Result<()> {
52        use nix::sys::signal::Signal;
53
54        let printer = Printer::from_flags(self.json, self.verbose);
55
56        let targets = parse_targets(&self.target);
57        let (mut processes, not_found) = resolve_targets_excluding_self(&targets);
58
59        if !not_found.is_empty() {
60            printer.warning(&format!("Not found: {}", not_found.join(", ")));
61        }
62
63        // Apply --in and --by filters
64        apply_filters(&mut processes, &self.in_dir, &self.by_name);
65
66        if processes.is_empty() {
67            return Err(ProcError::ProcessNotFound(self.target.clone()));
68        }
69
70        if self.dry_run {
71            printer.print_dry_run("resume", &processes);
72            return Ok(());
73        }
74
75        if !printer.ask_confirm("resume", &processes, self.yes)? {
76            return Ok(());
77        }
78
79        let mut succeeded = Vec::new();
80        let mut failed = Vec::new();
81
82        for proc in &processes {
83            match proc.send_signal(Signal::SIGCONT) {
84                Ok(()) => succeeded.push(proc.clone()),
85                Err(e) => failed.push((proc.clone(), e.to_string())),
86            }
87        }
88
89        printer.print_action_result("resume", &succeeded, &failed);
90
91        Ok(())
92    }
93
94    /// Windows stub
95    #[cfg(not(unix))]
96    pub fn execute(&self) -> Result<()> {
97        Err(ProcError::NotSupported(
98            "thaw (SIGCONT) is not supported on Windows".to_string(),
99        ))
100    }
101}