diff --git a/docs/cli/commands.json b/docs/cli/commands.json index e0497c1..76df61e 100644 --- a/docs/cli/commands.json +++ b/docs/cli/commands.json @@ -416,13 +416,22 @@ "full_cmd": [ "stop" ], - "usage": "stop", + "usage": "stop ", "subcommands": {}, - "args": [], + "args": [ + { + "name": "ID", + "usage": "", + "help": "The name of the daemon to stop", + "help_first_line": "The name of the daemon to stop", + "required": true, + "hide": false + } + ], "flags": [], "mounts": [], "hide": false, - "help": "Kill a running daemon", + "help": "Sends a stop signal to a daemon", "name": "stop", "aliases": [ "kill" diff --git a/docs/cli/index.md b/docs/cli/index.md index b3a3744..a4573f6 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -19,7 +19,7 @@ - [`pitchfork run [-f --force] [CMD]...`](/cli/run.md) - [`pitchfork start [NAME]...`](/cli/start.md) - [`pitchfork status `](/cli/status.md) -- [`pitchfork stop`](/cli/stop.md) +- [`pitchfork stop `](/cli/stop.md) - [`pitchfork supervisor `](/cli/supervisor.md) - [`pitchfork supervisor run [-f --force]`](/cli/supervisor/run.md) - [`pitchfork supervisor start [-f --force]`](/cli/supervisor/start.md) diff --git a/docs/cli/stop.md b/docs/cli/stop.md index 2c142df..1e529c7 100644 --- a/docs/cli/stop.md +++ b/docs/cli/stop.md @@ -1,6 +1,12 @@ # `pitchfork stop` -- **Usage**: `pitchfork stop` +- **Usage**: `pitchfork stop ` - **Aliases**: `kill` -Kill a running daemon +Sends a stop signal to a daemon + +## Arguments + +### `` + +The name of the daemon to stop diff --git a/pitchfork.usage.kdl b/pitchfork.usage.kdl index 38914d4..24d29f9 100644 --- a/pitchfork.usage.kdl +++ b/pitchfork.usage.kdl @@ -65,8 +65,9 @@ cmd "status" help="Display the status of a daemon" { alias "stat" arg "" } -cmd "stop" help="Kill a running daemon" { +cmd "stop" help="Sends a stop signal to a daemon" { alias "kill" + arg "" help="The name of the daemon to stop" } cmd "supervisor" subcommand_required=true help="Start, stop, and check the status of the pitchfork supervisor daemon" { cmd "run" help="Runs the internal pitchfork daemon in the foreground" { diff --git a/src/cli/list.rs b/src/cli/list.rs index 0bb021a..b279d58 100644 --- a/src/cli/list.rs +++ b/src/cli/list.rs @@ -19,14 +19,27 @@ impl List { .load_preset(comfy_table::presets::NOTHING) .set_content_arrangement(ContentArrangement::Dynamic); if !self.hide_header && console::user_attended() { - table.set_header(vec!["Name", "PID", "Status"]); + table.set_header(vec!["Name", "PID", "Status", ""]); } - for (id, daemon) in StateFile::get().daemons.iter() { + let sf = StateFile::get(); + for (id, daemon) in sf.daemons.iter() { table.add_row(vec![ Cell::new(id), - Cell::new(daemon.pid.to_string()), + Cell::new( + daemon + .pid + .as_ref() + .map(|p| p.to_string()) + .unwrap_or_default(), + ), Cell::new(daemon.status.style()), + Cell::new( + sf.disabled + .contains(id) + .then_some("disabled") + .unwrap_or_default(), + ), ]); } diff --git a/src/cli/run.rs b/src/cli/run.rs index d18fe52..f35b98c 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -28,7 +28,11 @@ impl Run { loop { match ipc.read().await? { IpcMessage::DaemonStart(daemon) => { - info!("Started daemon {} with pid {}", daemon.name, daemon.pid); + info!( + "Started daemon {} with pid {}", + daemon.name, + daemon.pid.unwrap() + ); break; } IpcMessage::DaemonFailed { name, error } => { diff --git a/src/cli/status.rs b/src/cli/status.rs index 18c5593..f73b20d 100644 --- a/src/cli/status.rs +++ b/src/cli/status.rs @@ -13,8 +13,10 @@ impl Status { let daemon = StateFile::get().daemons.get(&self.id); if let Some(daemon) = daemon { println!("Name: {}", self.id); - println!("PID: {}", daemon.pid); - println!("Status: {}", daemon.status); + if let Some(pid) = &daemon.pid { + println!("PID: {pid}"); + } + println!("Status: {}", daemon.status.style()); } else { warn!("Daemon {} not found", self.id); } diff --git a/src/cli/stop.rs b/src/cli/stop.rs index 64eea58..84e24c6 100644 --- a/src/cli/stop.rs +++ b/src/cli/stop.rs @@ -1,12 +1,26 @@ +use crate::cli::supervisor::kill_or_stop; +use crate::state_file::StateFile; use crate::Result; -/// Kill a running daemon +/// Sends a stop signal to a daemon #[derive(Debug, clap::Args)] #[clap(visible_alias = "kill", verbatim_doc_comment)] -pub struct Stop {} +pub struct Stop { + /// The name of the daemon to stop + id: String, +} impl Stop { pub async fn run(&self) -> Result<()> { + let pid_file = StateFile::get(); + if let Some(d) = pid_file.daemons.get(&self.id) { + if let Some(pid) = d.pid { + info!("stopping {} with pid {}", self.id, pid); + kill_or_stop(pid, true)?; + return Ok(()); + } + } + warn!("{} is not running", self.id); Ok(()) } } diff --git a/src/cli/supervisor/run.rs b/src/cli/supervisor/run.rs index 5e3ae71..fe12712 100644 --- a/src/cli/supervisor/run.rs +++ b/src/cli/supervisor/run.rs @@ -16,8 +16,10 @@ impl Run { pub async fn run(&self) -> Result<()> { let pid_file = StateFile::read(&*env::PITCHFORK_STATE_FILE)?; if let Some(d) = pid_file.daemons.get("pitchfork") { - if !(kill_or_stop(d.pid, self.force)?) { - return Ok(()); + if let Some(pid) = d.pid { + if !(kill_or_stop(pid, self.force)?) { + return Ok(()); + } } } diff --git a/src/cli/supervisor/start.rs b/src/cli/supervisor/start.rs index 482d863..11d803f 100644 --- a/src/cli/supervisor/start.rs +++ b/src/cli/supervisor/start.rs @@ -15,10 +15,12 @@ pub struct Start { impl Start { pub async fn run(&self) -> Result<()> { - let pid_file = StateFile::read(&*env::PITCHFORK_STATE_FILE)?; - if let Some(d) = pid_file.daemons.get("pitchfork") { - if !(kill_or_stop(d.pid, self.force)?) { - return Ok(()); + let sf = StateFile::get(); + if let Some(d) = sf.daemons.get("pitchfork") { + if let Some(pid) = d.pid { + if !(kill_or_stop(pid, self.force)?) { + return Ok(()); + } } } diff --git a/src/cli/supervisor/stop.rs b/src/cli/supervisor/stop.rs index 85b866e..8843dc0 100644 --- a/src/cli/supervisor/stop.rs +++ b/src/cli/supervisor/stop.rs @@ -1,6 +1,6 @@ use crate::cli::supervisor::kill_or_stop; use crate::state_file::StateFile; -use crate::{env, Result}; +use crate::Result; /// Stops the internal pitchfork daemon running in the background #[derive(Debug, clap::Args)] @@ -9,13 +9,16 @@ pub struct Stop {} impl Stop { pub async fn run(&self) -> Result<()> { - let pid_file = StateFile::read(&*env::PITCHFORK_STATE_FILE)?; + let pid_file = StateFile::get(); if let Some(d) = pid_file.daemons.get("pitchfork") { - info!("Stopping pitchfork daemon with pid {}", d.pid); - kill_or_stop(d.pid, true)?; - } else { - warn!("Pitchfork daemon is not running"); + if let Some(pid) = d.pid { + info!("Stopping pitchfork daemon with pid {}", pid); + if !(kill_or_stop(pid, false)?) { + return Ok(()); + } + } } + warn!("Pitchfork daemon is not running"); Ok(()) } } diff --git a/src/state_file.rs b/src/state_file.rs index 63f68db..e37efe9 100644 --- a/src/state_file.rs +++ b/src/state_file.rs @@ -16,7 +16,7 @@ pub struct StateFile { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct StateFileDaemon { pub name: String, - pub pid: u32, + pub pid: Option, pub status: DaemonStatus, } @@ -27,6 +27,7 @@ pub enum DaemonStatus { Failed(String), Waiting, Running, + Stopped, } impl DaemonStatus { @@ -36,6 +37,7 @@ impl DaemonStatus { DaemonStatus::Failed(_) => console::style(s).red().to_string(), DaemonStatus::Waiting => console::style(s).yellow().to_string(), DaemonStatus::Running => console::style(s).green().to_string(), + DaemonStatus::Stopped => console::style(s).dim().to_string(), } } } diff --git a/src/supervisor.rs b/src/supervisor.rs index c76a043..ee0e3e2 100644 --- a/src/supervisor.rs +++ b/src/supervisor.rs @@ -60,7 +60,7 @@ impl Supervisor { let daemon = StateFileDaemon { name: "pitchfork".into(), - pid, + pid: Some(pid), status: DaemonStatus::Running, }; self.state_file.daemons.insert("pitchfork".into(), daemon); @@ -103,13 +103,19 @@ impl Supervisor { self.handle_ipc(msg, send).await } Event::Signal => { - info!("received SIGTERM, stopping"); + info!("received signal, stopping"); self.close(); exit(0) } Event::DaemonStop(daemon) => { - self.active_pids.remove(&daemon.pid); - self.state_file.daemons.remove(&daemon.name); + self.active_pids.remove(&daemon.pid.unwrap()); + self.state_file + .daemons + .entry(daemon.name.clone()) + .and_modify(|d| { + d.pid = None; + d.status = DaemonStatus::Stopped; + }); self.state_file.write()?; Ok(()) } @@ -186,7 +192,7 @@ impl Supervisor { info!("started daemon {name} with pid {pid}"); let daemon = StateFileDaemon { name: name.to_string(), - pid, + pid: Some(pid), status: DaemonStatus::Running, }; self.state_file