Add func: log(with some bug)
This commit is contained in:
parent
9297451aa2
commit
5f9314052e
13
Cargo.toml
13
Cargo.toml
@ -7,11 +7,12 @@ description = "A process manager in Rust"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
sysinfo = "0.33.1"
|
||||
tabled = "0.17.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
dirs = "5.0"
|
||||
serde_json = "1.0"
|
||||
clap = { version = "4.4.11", features = ["derive"] }
|
||||
sysinfo = "0.29.11"
|
||||
tabled = "0.14.0"
|
||||
serde = { version = "1.0.193", features = ["derive"] }
|
||||
dirs = "5.0.1"
|
||||
serde_json = "1.0.108"
|
||||
crossterm = "0.28.1"
|
||||
once_cell = "1.18.0"
|
||||
ctrlc = "3.4.1"
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::config::dump::DumpConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sysinfo::{System, Users};
|
||||
use sysinfo::{ProcessExt, System, SystemExt, UserExt};
|
||||
use tabled::{Table, Tabled};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@ -83,8 +83,7 @@ pub fn read_pmr_processes() -> Vec<PmrProcess> {
|
||||
}
|
||||
|
||||
pub fn list_processes(system: bool) {
|
||||
let mut sys = System::new_all();
|
||||
let users = Users::new_with_refreshed_list();
|
||||
let mut sys = System::new();
|
||||
sys.refresh_all();
|
||||
|
||||
if system {
|
||||
@ -93,7 +92,7 @@ pub fn list_processes(system: bool) {
|
||||
.iter()
|
||||
.map(|(&pid, process)| ProcessInfo {
|
||||
id: "0".to_string(),
|
||||
name: process.name().to_string_lossy().to_string(),
|
||||
name: process.name().to_string(),
|
||||
namespace: "default".to_string(),
|
||||
version: "N/A".to_string(),
|
||||
pid: pid.to_string(),
|
||||
@ -104,7 +103,7 @@ pub fn list_processes(system: bool) {
|
||||
mem: format!("{:.1} MB", process.memory() as f64 / 1024.0 / 1024.0),
|
||||
user: process
|
||||
.user_id()
|
||||
.and_then(|uid| users.get_user_by_id(uid))
|
||||
.and_then(|uid| sys.get_user_by_id(uid))
|
||||
.map_or("N/A".to_string(), |u| u.name().to_string()),
|
||||
})
|
||||
.collect();
|
||||
@ -133,7 +132,7 @@ pub fn list_processes(system: bool) {
|
||||
mem: format!("{:.1} MB", sys_proc.memory() as f64 / 1024.0 / 1024.0),
|
||||
user: sys_proc
|
||||
.user_id()
|
||||
.and_then(|uid| users.get_user_by_id(uid))
|
||||
.and_then(|uid| sys.get_user_by_id(uid))
|
||||
.map_or("N/A".to_string(), |u| u.name().to_string()),
|
||||
}
|
||||
} else {
|
||||
|
89
src/commands/log.rs
Normal file
89
src/commands/log.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use super::super::config::dump::DumpConfig;
|
||||
use super::super::config::log_path;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader, Seek, SeekFrom};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
pub fn tail_log(target: String) -> io::Result<()> {
|
||||
let dump_config = DumpConfig::get_instance();
|
||||
|
||||
// 解析目标ID
|
||||
let pmr_id = match target.parse::<u32>() {
|
||||
Ok(id) => id,
|
||||
Err(_) => {
|
||||
// 如果不是数字,尝试按名称查找
|
||||
match dump_config.list_processes() {
|
||||
Ok(processes) => {
|
||||
if let Some(process) = processes.iter().find(|p| p.name == target) {
|
||||
process.pmr_id
|
||||
} else {
|
||||
eprintln!("找不到进程: {}", target);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("无法获取进程列表: {}", e);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 获取日志文件路径
|
||||
let log_path = match log_path::get_log_path(pmr_id) {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
eprintln!("无法获取日志文件路径: {}", e);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// 检查日志文件是否存在
|
||||
if !log_path.exists() {
|
||||
eprintln!("日志文件不存在: {:?}", log_path);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("正在查看日志文件: {:?}", log_path);
|
||||
println!("按 Ctrl+C 退出日志查看...");
|
||||
|
||||
// 打开日志文件
|
||||
let mut file = match File::open(&log_path) {
|
||||
Ok(file) => file,
|
||||
Err(e) => {
|
||||
eprintln!("无法打开日志文件: {}", e);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// 移动到文件末尾
|
||||
if let Err(e) = file.seek(SeekFrom::End(0)) {
|
||||
eprintln!("无法定位到文件末尾: {}", e);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut buffer = String::new();
|
||||
|
||||
// 持续读取新的日志内容
|
||||
loop {
|
||||
match reader.read_line(&mut buffer) {
|
||||
Ok(0) => {
|
||||
// 没有新的内容,等待一下
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
}
|
||||
Ok(_) => {
|
||||
// 打印新的内容
|
||||
print!("{}", buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("读取日志时出错: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
pub mod delete;
|
||||
pub mod list;
|
||||
pub mod log;
|
||||
pub mod restart;
|
||||
pub mod start;
|
||||
pub mod stop;
|
||||
|
||||
pub use log::tail_log;
|
||||
|
@ -1,16 +1,20 @@
|
||||
use super::super::base::process::PmrProcessInfo;
|
||||
use super::super::config::dump::DumpConfig;
|
||||
use super::super::config::log_path;
|
||||
use super::list::list_processes;
|
||||
use super::start::start_process;
|
||||
use super::stop::stop_process;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Stdio;
|
||||
|
||||
pub fn restart_process(
|
||||
config: Option<PathBuf>,
|
||||
namespace: Option<String>,
|
||||
target: Option<String>,
|
||||
args: Vec<String>,
|
||||
) {
|
||||
) -> io::Result<()> {
|
||||
let dump_config = DumpConfig::get_instance();
|
||||
|
||||
// 如果指定了target,先检查是否是已存在的进程
|
||||
@ -19,34 +23,49 @@ pub fn restart_process(
|
||||
// 尝试将target解析为pmr_id
|
||||
if let Ok(pmr_id) = target_str.parse::<u32>() {
|
||||
if let Some(process) = processes.iter().find(|p| p.pmr_id == pmr_id) {
|
||||
restart_existing_process(process);
|
||||
return;
|
||||
restart_existing_process(process)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
// 按名称查找进程
|
||||
if let Some(process) = processes.iter().find(|p| p.name == *target_str) {
|
||||
restart_existing_process(process);
|
||||
return;
|
||||
restart_existing_process(process)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是重启已存在的进程,就当作普通的启动处理
|
||||
start_process(config, namespace, "default".to_string(), target, args);
|
||||
start_process(config, namespace, "default".to_string(), target, args)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn restart_existing_process(process: &PmrProcessInfo) {
|
||||
|
||||
fn restart_existing_process(process: &PmrProcessInfo) -> io::Result<()> {
|
||||
println!("正在重启进程 '{}'...", process.name);
|
||||
|
||||
// 先停止进程
|
||||
stop_process(&process.pmr_id.to_string(), false);
|
||||
|
||||
// 获取日志文件路径
|
||||
let log_path = log_path::get_log_path(process.pmr_id)?;
|
||||
|
||||
// 打开日志文件(追加模式)
|
||||
let log_file = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&log_path)?;
|
||||
|
||||
// 使用同一个文件句柄来重定向标准输出和标准错误
|
||||
let stdout_log = log_file.try_clone()?;
|
||||
let stderr_log = log_file.try_clone()?;
|
||||
|
||||
// 重新启动进程
|
||||
let mut cmd = std::process::Command::new(&process.program);
|
||||
cmd.args(&process.args)
|
||||
.stdout(std::process::Stdio::inherit())
|
||||
.stderr(std::process::Stdio::inherit());
|
||||
.stdout(Stdio::from(stdout_log))
|
||||
.stderr(Stdio::from(stderr_log));
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(child) => {
|
||||
@ -65,9 +84,14 @@ fn restart_existing_process(process: &PmrProcessInfo) {
|
||||
|
||||
// 显示进程列表
|
||||
list_processes(false);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("重启进程失败: {}", e);
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("重启进程失败: {}", e),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
use super::super::base::process::PmrProcessInfo;
|
||||
use super::super::config::log_path;
|
||||
use super::super::config::dump::DumpConfig;
|
||||
use super::list::list_processes;
|
||||
use super::stop::stop_process;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, Read};
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
@ -21,77 +23,84 @@ pub fn start_process(
|
||||
namespace: String,
|
||||
target: Option<String>,
|
||||
args: Vec<String>,
|
||||
) {
|
||||
) -> io::Result<()> {
|
||||
let dump_config = DumpConfig::get_instance();
|
||||
// 获取当前工作目录
|
||||
let workdir = env::current_dir()
|
||||
.unwrap_or_else(|_| PathBuf::from("."))
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
.to_string();
|
||||
|
||||
// 获取进程名称
|
||||
let process_name = name.unwrap_or_else(|| {
|
||||
target
|
||||
.as_ref()
|
||||
.map(|s| s.split('/').last().unwrap_or(s))
|
||||
.unwrap_or("unknown")
|
||||
.to_string()
|
||||
});
|
||||
|
||||
// 如果指定了target,先检查是否是已存在的进程
|
||||
if let Some(ref target_str) = target {
|
||||
if let Ok(processes) = dump_config.list_processes() {
|
||||
// 按pmr_id查找进程
|
||||
// 尝试将target解析为pmr_id
|
||||
if let Ok(pmr_id) = target_str.parse::<u32>() {
|
||||
if let Some(process) = processes.iter().find(|p| p.pmr_id == pmr_id) {
|
||||
start_existing_process(process);
|
||||
return;
|
||||
start_existing_process(process)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
// 按name查找进程
|
||||
// 按名称查找进程
|
||||
if let Some(process) = processes.iter().find(|p| p.name == *target_str) {
|
||||
start_existing_process(process);
|
||||
return;
|
||||
start_existing_process(process)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否已存在同名进程在同一namespace中
|
||||
let process_name = name.clone().unwrap_or_else(|| {
|
||||
target.clone().unwrap_or_else(|| {
|
||||
if let Some(ref config_path) = config {
|
||||
let mut file = File::open(config_path).expect("Failed to open config file");
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)
|
||||
.expect("Failed to read config file");
|
||||
let config: Config =
|
||||
serde_json::from_str(&contents).expect("Failed to parse config file");
|
||||
config.name
|
||||
} else {
|
||||
"unnamed".to_string()
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if let Ok(processes) = dump_config.list_processes() {
|
||||
if let Some(_existing) = processes
|
||||
.iter()
|
||||
.find(|p| p.name == process_name && p.namespace == namespace)
|
||||
{
|
||||
println!(
|
||||
"\n进程 '{}' 在命名空间 '{}' 中已经存在:",
|
||||
process_name, namespace
|
||||
);
|
||||
list_processes(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果指定了配置文件,从配置文件启动
|
||||
if let Some(config_path) = config {
|
||||
// 从配置文件启动
|
||||
let mut file = File::open(config_path).expect("无法打开配置文件");
|
||||
if !config_path.exists() {
|
||||
eprintln!("配置文件不存在: {:?}", config_path);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 读取配置文件
|
||||
let mut file = File::open(&config_path)?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)
|
||||
.expect("无法读取配置文件");
|
||||
file.read_to_string(&mut contents)?;
|
||||
|
||||
let config: Config = serde_json::from_str(&contents).expect("无法解析配置文件");
|
||||
|
||||
let new_id = dump_config.add_process(
|
||||
process_name.clone(),
|
||||
namespace.clone(),
|
||||
workdir.clone(),
|
||||
config.program.clone(),
|
||||
0,
|
||||
"starting".to_string(),
|
||||
config.args.clone(),
|
||||
)?;
|
||||
|
||||
// 获取日志文件路径
|
||||
let log_path = log_path::get_log_path(new_id)?;
|
||||
|
||||
// 打开日志文件(追加模式)
|
||||
let log_file = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&log_path)?;
|
||||
|
||||
// 使用同一个文件句柄来重定向标准输出和标准错误
|
||||
let stdout_log = log_file.try_clone()?;
|
||||
let stderr_log = log_file.try_clone()?;
|
||||
|
||||
// 启动进程
|
||||
let mut cmd = Command::new(&config.program);
|
||||
cmd.args(&config.args)
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit());
|
||||
.stdout(Stdio::from(stdout_log))
|
||||
.stderr(Stdio::from(stderr_log));
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(child) => {
|
||||
@ -99,27 +108,49 @@ pub fn start_process(
|
||||
println!("启动进程 '{}' PID: {}", process_name, pid);
|
||||
|
||||
dump_config
|
||||
.add_process(
|
||||
process_name,
|
||||
namespace,
|
||||
workdir,
|
||||
config.program,
|
||||
pid,
|
||||
"running".to_string(),
|
||||
config.args,
|
||||
)
|
||||
.expect("无法将进程添加到配置文件");
|
||||
.update_process_status(new_id, pid, "running".to_string())
|
||||
.expect("无法更新进程状态");
|
||||
|
||||
list_processes(false);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("启动进程失败: {}", e);
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("启动进程失败: {}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if let Some(target_program) = target {
|
||||
// 直接启动程序
|
||||
let new_id = dump_config.add_process(
|
||||
process_name.clone(),
|
||||
namespace.clone(),
|
||||
workdir.clone(),
|
||||
target_program.clone(),
|
||||
0,
|
||||
"starting".to_string(),
|
||||
args.clone(),
|
||||
)?;
|
||||
|
||||
// 获取日志文件路径
|
||||
let log_path = log_path::get_log_path(new_id)?;
|
||||
|
||||
// 打开日志文件(追加模式)
|
||||
let log_file = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&log_path)?;
|
||||
|
||||
// 使用同一个文件句柄来重定向标准输出和标准错误
|
||||
let stdout_log = log_file.try_clone()?;
|
||||
let stderr_log = log_file.try_clone()?;
|
||||
|
||||
// 启动进程
|
||||
let mut cmd = Command::new(&target_program);
|
||||
cmd.args(&args)
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit());
|
||||
.stdout(Stdio::from(stdout_log))
|
||||
.stderr(Stdio::from(stderr_log));
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(child) => {
|
||||
@ -127,46 +158,52 @@ pub fn start_process(
|
||||
println!("启动进程 '{}' PID: {}", process_name, pid);
|
||||
|
||||
dump_config
|
||||
.add_process(
|
||||
process_name,
|
||||
namespace,
|
||||
workdir,
|
||||
target_program,
|
||||
pid,
|
||||
"running".to_string(),
|
||||
args,
|
||||
)
|
||||
.expect("无法将进程添加到配置文件");
|
||||
.update_process_status(new_id, pid, "running".to_string())
|
||||
.expect("无法更新进程状态");
|
||||
list_processes(false);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("启动进程失败: {}", e);
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("启动进程失败: {}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("错误: 必须指定 --config 或 target");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_existing_process(process: &PmrProcessInfo) {
|
||||
fn start_existing_process(process: &PmrProcessInfo) -> io::Result<()> {
|
||||
if process.status == "running" {
|
||||
println!("进程 '{}' 已经在运行中,PID: {}", process.name, process.pid);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 保存当前工作目录
|
||||
let original_dir = env::current_dir().expect("无法获取当前工作目录");
|
||||
// 先停止进程
|
||||
stop_process(&process.pmr_id.to_string(), false);
|
||||
|
||||
// 切换到进程的工作目录
|
||||
if let Err(e) = env::set_current_dir(&process.workdir) {
|
||||
eprintln!("无法切换到工作目录 {}: {}", process.workdir, e);
|
||||
return;
|
||||
}
|
||||
// 获取日志文件路径
|
||||
let log_path = log_path::get_log_path(process.pmr_id)?;
|
||||
|
||||
// 打开日志文件(追加模式)
|
||||
let log_file = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&log_path)?;
|
||||
|
||||
// 使用同一个文件句柄来重定向标准输出和标准错误
|
||||
let stdout_log = log_file.try_clone()?;
|
||||
let stderr_log = log_file.try_clone()?;
|
||||
|
||||
// 重新启动进程
|
||||
let mut cmd = Command::new(&process.program);
|
||||
cmd.args(&process.args)
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit());
|
||||
.stdout(Stdio::from(stdout_log))
|
||||
.stderr(Stdio::from(stderr_log));
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(child) => {
|
||||
@ -180,14 +217,14 @@ fn start_existing_process(process: &PmrProcessInfo) {
|
||||
|
||||
// 显示进程列表
|
||||
list_processes(false);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("启动进程失败: {}", e);
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("启动进程失败: {}", e),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复原始工作目录
|
||||
if let Err(e) = env::set_current_dir(&original_dir) {
|
||||
eprintln!("警告:无法恢复原始工作目录: {}", e);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,8 @@ impl DumpConfig {
|
||||
let json: serde_json::Value = serde_json::from_str(&file_contents)?;
|
||||
|
||||
// 手动构建进程列表
|
||||
let processes = if let Some(processes) = json.get("processes").and_then(|v| v.as_array()) {
|
||||
let processes =
|
||||
if let Some(processes) = json.get("processes").and_then(|v| v.as_array()) {
|
||||
processes
|
||||
.iter()
|
||||
.map(|p| PmrProcessInfo {
|
||||
@ -93,7 +94,7 @@ impl DumpConfig {
|
||||
pid: u32,
|
||||
status: String,
|
||||
args: Vec<String>,
|
||||
) -> io::Result<()> {
|
||||
) -> io::Result<u32> {
|
||||
let mut data = self.data.lock().unwrap();
|
||||
let new_id = data.processes.iter().map(|p| p.pmr_id).max().unwrap_or(0) + 1;
|
||||
|
||||
@ -109,7 +110,8 @@ impl DumpConfig {
|
||||
restarts: 0, // 初始化重启次数为0
|
||||
});
|
||||
|
||||
self.save_data(&data)
|
||||
self.save_data(&data)?;
|
||||
Ok(new_id)
|
||||
}
|
||||
|
||||
pub fn delete_process(&self, id: u32) -> io::Result<()> {
|
||||
|
17
src/config/log_path.rs
Normal file
17
src/config/log_path.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use dirs;
|
||||
|
||||
pub fn get_log_path(pmr_id: u32) -> io::Result<PathBuf> {
|
||||
let home_dir = dirs::home_dir()
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Home directory not found"))?;
|
||||
let log_dir = home_dir.join(".pmr").join("logs");
|
||||
|
||||
// 确保日志目录存在
|
||||
if !log_dir.exists() {
|
||||
fs::create_dir_all(&log_dir)?;
|
||||
}
|
||||
|
||||
Ok(log_dir.join(format!("{}.log", pmr_id)))
|
||||
}
|
@ -1 +1,2 @@
|
||||
pub mod dump;
|
||||
pub mod log_path;
|
||||
|
43
src/main.rs
43
src/main.rs
@ -8,6 +8,7 @@ use commands::list::list_processes;
|
||||
use commands::restart::restart_process;
|
||||
use commands::start::start_process;
|
||||
use commands::stop::stop_process;
|
||||
use commands::tail_log;
|
||||
use config::dump::DumpConfig;
|
||||
|
||||
fn config_init() -> std::io::Result<()> {
|
||||
@ -49,7 +50,12 @@ enum Commands {
|
||||
},
|
||||
|
||||
/// List running processes
|
||||
#[command(alias = "ls")]
|
||||
#[command(
|
||||
alias = "ls",
|
||||
alias = "ps",
|
||||
alias = "status",
|
||||
about = "List running processes. Alias: ls, ps, status"
|
||||
)]
|
||||
List {
|
||||
/// Show all system processes
|
||||
#[arg(long)]
|
||||
@ -57,7 +63,11 @@ enum Commands {
|
||||
},
|
||||
|
||||
/// Delete a process
|
||||
#[command(alias = "rm")]
|
||||
#[command(
|
||||
alias = "rm",
|
||||
alias = "del",
|
||||
about = "Delete a process. Alias: rm, del"
|
||||
)]
|
||||
Delete {
|
||||
/// Process ID or name
|
||||
target: String,
|
||||
@ -86,6 +96,13 @@ enum Commands {
|
||||
#[arg(last = true)]
|
||||
args: Vec<String>,
|
||||
},
|
||||
|
||||
/// View logs of a process
|
||||
#[command(alias = "logs")]
|
||||
Log {
|
||||
/// Process ID or name
|
||||
target: String,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -108,7 +125,13 @@ fn main() {
|
||||
eprintln!("错误: 必须指定 --config 或 target");
|
||||
return;
|
||||
}
|
||||
start_process(config, name, namespace, target, args);
|
||||
match start_process(config, name, namespace, target, args) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
eprintln!("启动进程失败: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Commands::List { system } => {
|
||||
list_processes(system);
|
||||
@ -129,7 +152,19 @@ fn main() {
|
||||
eprintln!("错误: 必须指定 --config 或 target");
|
||||
return;
|
||||
}
|
||||
restart_process(config, Some(namespace), target, args);
|
||||
match restart_process(config, Some(namespace), target, args) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
eprintln!("重启进程失败: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Commands::Log { target } => {
|
||||
if let Err(e) = tail_log(target) {
|
||||
eprintln!("查看日志失败: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user