diff --git a/README.md b/README.md index b39c85c..7301d7a 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,83 @@ # Process Management Controller (PMC) ## Overview PMC (Process Management Controller) is a simple PM2 alternative written in Rust. It provides a command-line/api interface to start, stop, restart, and manage fork processes ## Features - Start, stop, and restart processes. - List all running processes with customizable output formats. - Retrieve detailed information about a specific process. - Use HTTP/rust api to control processes. ## Usage ```bash # Start/Restart a process -pmc start <id> or <script> [--name <name>] +pmc start <id/name> or <script> [--name <name>] # Stop/Kill a process -pmc stop <id> +pmc stop <id/name> # Remove a process -pmc remove <id> +pmc remove <id/name> # Get process info -pmc info <id> +pmc info <id/name> # Get process env -pmc env <id> +pmc env <id/name> + +# Save all processes to dumpfile +pmc save + +# Restore all processes +pmc restore # List all processes pmc list [--format <raw|json|default>] # Get process logs -pmc logs <id> [--lines <num_lines>] +pmc logs <id/name> [--lines <num_lines>] + +# Reset process index +pmc daemon reset + +# Stop daemon +pmc daemon stop + +# Start/Restart daemon +pmc daemon start + +# Check daemon health +pmc daemon health + +# Add new Ssrver +pmc server new + +# List servers +pmc server list [--format <format>] + +# Remove server +pmc server remove <name> + +# Set default server +pmc server default [<name>] ``` -For more commands, check out `pmc --help` +For more command information, check out `pmc --help` ### Installation Pre-built binaries for Linux, MacOS, and WSL can be found on the [releases](releases) page. There is no windows support yet. Install from crates.io using `cargo install pmc` (requires clang++) #### Building - Clone the project - Open a terminal in the project folder - Check if you have cargo (Rust's package manager) installed, just type in `cargo` - If cargo is installed, run `cargo build --release` - Put the executable into one of your PATH entries, usually `/bin/` or `/usr/bin/` diff --git a/src/main.rs b/src/main.rs index 4e15c09..f3bdd00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,245 +1,245 @@ mod cli; mod daemon; mod globals; mod webui; use clap::{Parser, Subcommand}; use clap_verbosity_flag::{LogLevel, Verbosity}; use macros_rs::{str, string, then}; use update_informer::{registry, Check}; use crate::{ cli::{internal::Internal, Args, Item}, globals::defaults, }; #[derive(Copy, Clone, Debug, Default)] struct NoneLevel; impl LogLevel for NoneLevel { fn default() -> Option<log::Level> { None } } #[derive(Parser)] #[command(version = str!(cli::get_version(false)))] struct Cli { #[command(subcommand)] command: Commands, #[clap(flatten)] verbose: Verbosity<NoneLevel>, } #[derive(Subcommand)] enum Daemon { /// Reset process index #[command(visible_alias = "clean")] Reset, /// Stop daemon #[command(visible_alias = "kill")] Stop, /// Restart daemon #[command(visible_alias = "restart", visible_alias = "start")] Restore { /// Daemon api #[arg(long)] api: bool, /// WebUI using api #[arg(long)] webui: bool, }, - /// Check daemon + /// Check daemon health #[command(visible_alias = "info", visible_alias = "status")] Health { /// Format output #[arg(long, default_value_t = string!("default"))] format: String, }, } #[derive(Subcommand)] enum Server { /// Add new server #[command(visible_alias = "add")] New, /// List servers #[command(visible_alias = "ls")] List { /// Format output #[arg(long, default_value_t = string!("default"))] format: String, }, /// Remove server #[command(visible_alias = "rm")] Remove { /// Server name name: String, }, /// Set default server #[command(visible_alias = "set")] Default { /// Server name name: Option<String>, }, } // add pmc restore command #[derive(Subcommand)] enum Commands { /// Start/Restart a process #[command(visible_alias = "restart")] Start { /// Process name #[arg(long)] name: Option<String>, #[clap(value_parser = cli::validate::<Args>)] args: Args, /// Watch to reload path #[arg(long)] watch: Option<String>, /// Server #[arg(short, long)] server: Option<String>, }, /// Stop/Kill a process #[command(visible_alias = "kill")] Stop { #[clap(value_parser = cli::validate::<Item>)] item: Item, /// Server #[arg(short, long)] server: Option<String>, }, /// Stop then remove a process #[command(visible_alias = "rm")] Remove { #[clap(value_parser = cli::validate::<Item>)] item: Item, /// Server #[arg(short, long)] server: Option<String>, }, /// Get env of a process #[command(visible_alias = "cmdline")] Env { #[clap(value_parser = cli::validate::<Item>)] item: Item, /// Server #[arg(short, long)] server: Option<String>, }, /// Get information of a process #[command(visible_alias = "info")] Details { #[clap(value_parser = cli::validate::<Item>)] item: Item, /// Format output #[arg(long, default_value_t = string!("default"))] format: String, /// Server #[arg(short, long)] server: Option<String>, }, /// List all processes #[command(visible_alias = "ls")] List { /// Format output #[arg(long, default_value_t = string!("default"))] format: String, /// Server #[arg(short, long)] server: Option<String>, }, /// Restore all processes #[command(visible_alias = "resurrect")] Restore { /// Server #[arg(short, long)] server: Option<String>, }, /// Save all processes to dumpfile #[command(visible_alias = "store")] Save { /// Server #[arg(short, long)] server: Option<String>, }, /// Get logs from a process Logs { #[clap(value_parser = cli::validate::<Item>)] item: Item, #[arg(long, default_value_t = 15, help = "")] lines: usize, /// Server #[arg(short, long)] server: Option<String>, }, /// Daemon management #[command(visible_alias = "agent", visible_alias = "bgd")] Daemon { #[command(subcommand)] command: Daemon, }, /// Server management #[command(visible_alias = "remote", visible_alias = "srv")] Server { #[command(subcommand)] command: Server, }, } fn main() { let cli = Cli::parse(); let mut env = env_logger::Builder::new(); let level = cli.verbose.log_level_filter(); let informer = update_informer::new(registry::Crates, "pmc", env!("CARGO_PKG_VERSION")); if let Some(version) = informer.check_version().ok().flatten() { println!("{} New version is available: {version}", *pmc::helpers::WARN); } globals::init(); env.filter_level(level).init(); match &cli.command { Commands::Start { name, args, watch, server } => cli::start(name, args, watch, &defaults(server)), Commands::Stop { item, server } => cli::stop(item, &defaults(server)), Commands::Remove { item, server } => cli::remove(item, &defaults(server)), Commands::Restore { server } => Internal::restore(&defaults(server)), Commands::Save { server } => Internal::save(&defaults(server)), Commands::Env { item, server } => cli::env(item, &defaults(server)), Commands::Details { item, format, server } => cli::info(item, format, &defaults(server)), Commands::List { format, server } => Internal::list(format, &defaults(server)), Commands::Logs { item, lines, server } => cli::logs(item, lines, &defaults(server)), Commands::Daemon { command } => match command { Daemon::Stop => daemon::stop(), Daemon::Reset => daemon::reset(), Daemon::Health { format } => daemon::health(format), Daemon::Restore { api, webui } => daemon::restart(api, webui, level.as_str() != "OFF"), }, Commands::Server { command } => match command { Server::New => cli::server::new(), Server::Remove { name } => cli::server::remove(name), Server::Default { name } => cli::server::default(name), Server::List { format } => cli::server::list(format, cli.verbose.log_level()), }, }; if !matches!(&cli.command, Commands::Daemon { .. }) && !matches!(&cli.command, Commands::Server { .. }) && !matches!(&cli.command, Commands::Save { .. }) && !matches!(&cli.command, Commands::Env { .. }) { then!(!daemon::pid::exists(), daemon::restart(&false, &false, false)); } }