A lightweight CLI tool that connects to a remote server over SSH and executes PM2 process manager commands.
1use crate::pm2::run_pm2_command;
2use clap::{Arg, Command as ClapCommand};
3use owo_colors::OwoColorize;
4use std::env;
5
6pub mod pm2;
7
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9 let banner = format!(
10 "{}\nConnects to a remote server via SSH and executes PM2 commands",
11 r#"
12 ██████ ███ ███ ██████ ██████
13 ██ ██ ████ ████ ██ ██
14 ██████ ██ ████ ██ █████ █████
15 ██ ██ ██ ██ ██ ██
16 ██ ██ ██ ███████ ███████
17"#
18 .cyan()
19 );
20 let matches = ClapCommand::new("pm22")
21 .about(&banner)
22 .version(env!("CARGO_PKG_VERSION"))
23 .author("Tsiry Sandratraina <tsiry.sndr@rocksky.app>")
24 .arg(
25 Arg::new("host")
26 .short('h')
27 .long("host")
28 .default_value("PM22_HOST")
29 .help("Host to connect to, with username (e.g., user@host)"),
30 )
31 .arg(
32 Arg::new("port")
33 .short('p')
34 .long("port")
35 .default_value("22")
36 .help("Port to connect to (default: 22)"),
37 )
38 .arg(
39 Arg::new("verbose")
40 .short('v')
41 .long("verbose")
42 .action(clap::ArgAction::SetTrue)
43 .help("Enable verbose output"),
44 )
45 .arg(
46 Arg::new("key")
47 .short('k')
48 .long("key")
49 .default_value("~/.ssh/id_rsa")
50 .help("SSH private key file (default: ~/.ssh/id_rsa)"),
51 )
52 .arg(
53 Arg::new("cmd")
54 .required(true)
55 .help("PM2 Command to run on the remote server, e.g., ps, status, start, stop, restart, delete, logs, etc.")
56 )
57 .arg(
58 Arg::new("args")
59 .trailing_var_arg(true)
60 .allow_hyphen_values(true)
61 .num_args(0..)
62 .help("Arguments to pass to pm2 command"),
63 )
64 .get_matches();
65
66 let verbose = matches.get_flag("verbose");
67 init_logger(verbose);
68
69 let host = env::var("PM22_HOST")
70 .unwrap_or_else(|_| matches.get_one::<String>("host").unwrap().to_string());
71 let host = match host.as_str() {
72 "PM22_HOST" => env::var("PM22_HOST")?,
73 _ => host,
74 };
75 let port = env::var("PM22_PORT")
76 .unwrap_or_else(|_| matches.get_one::<String>("port").unwrap().to_string());
77 matches.get_one::<String>("port").unwrap();
78 let key = env::var("PM22_KEY")
79 .unwrap_or_else(|_| matches.get_one::<String>("key").unwrap().to_string());
80 let cmd = matches.get_one::<String>("cmd").unwrap();
81 let args: Vec<&String> = matches
82 .get_many::<String>("args")
83 .map(|vals| vals.collect())
84 .unwrap_or_default();
85
86 run_pm2_command(
87 host.trim(),
88 port.parse().unwrap_or(22),
89 key.trim(),
90 cmd,
91 args,
92 )?;
93 Ok(())
94}
95
96pub fn init_logger(verbose: bool) {
97 let level = if verbose { "debug" } else { "warn" };
98 unsafe { std::env::set_var("RUST_LOG", level) };
99 env_logger::init();
100}