Rust进程控制库proc-exit的使用:安全终止程序与自定义退出码管理
Rust进程控制库proc-exit的使用:安全终止程序与自定义退出码管理
特性
i32
新类型用于退出码- 可以表示任何有效的退出码
- 类型安全,操作仅限于退出码的有效范围
- 包含标准退出码和信号退出码
- 可与
main
、std::process
和std::io::Error
集成 - 支持静默退出(通过其他方式报告错误消息)
安装
添加到你的 Cargo.toml
:
proc-exit = "2.0.2"
使用示例
基本用法
use proc_exit::prelude::*;
fn main() {
if some_condition() {
// 使用标准退出码
proc_exit::exit(proc_exit::Code::USAGE);
}
// 使用自定义退出码
proc_exit::exit(42);
}
与main集成
use proc_exit::prelude::*;
fn main() -> proc_exit::ExitResult {
// 你的程序逻辑
if some_error_condition() {
// 返回错误退出码
return proc_exit::Code::DATA_ERR.to_result();
}
// 成功返回
proc_exit::Code::SUCCESS.to_result()
}
与std::process和std::io::Error集成
use proc_exit::prelude::*;
use std::fs::File;
use std::io;
fn open_file() -> proc_exit::ExitResult {
File::open("not_exist.txt")
.map_err(|e| proc_exit::Code::NO_INPUT.with_message(e))?;
Ok(())
}
fn main() -> proc_exit::ExitResult {
open_file()?;
Ok(())
}
完整示例
use proc_exit::prelude::*;
fn main() -> proc_exit::ExitResult {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
eprintln!("Usage: {} <filename>", args[0]);
return proc_exit::Code::USAGE.to_result();
}
let filename = &args[1];
let content = std::fs::read_to_string(filename)
.map_err(|e| proc_exit::Code::NO_INPUT.with_message(e))?;
if content.is_empty() {
eprintln!("Error: File is empty");
return proc_exit::Code::DATA_ERR.to_result();
}
println!("File content: {}", content);
// 成功退出
proc_exit::Code::SUCCESS.to_result()
}
完整示例demo
下面是一个更完整的文件处理程序示例,展示了proc-exit库的各种用法:
use proc_exit::prelude::*;
use std::fs;
use std::path::Path;
// 检查文件是否存在且可读
fn check_file(filename: &str) -> proc_exit::ExitResult {
if !Path::new(filename).exists() {
eprintln!("Error: File '{}' does not exist", filename);
return proc_exit::Code::NO_INPUT.to_result();
}
// 检查文件权限
match fs::metadata(filename) {
Ok(metadata) => {
if metadata.permissions().readonly() {
eprintln!("Error: File '{}' is read-only", filename);
return proc_exit::Code::NO_PERM.to_result();
}
}
Err(e) => {
return proc_exit::Code::OS_ERR
.with_message(format!("Failed to access file metadata: {}", e))
.to_result();
}
}
Ok(())
}
// 处理文件内容
fn process_file(filename: &str) -> proc_exit::ExitResult {
let content = fs::read_to_string(filename)
.map_err(|e| proc_exit::Code::IO_ERR.with_message(e))?;
if content.trim().is_empty() {
eprintln!("Warning: File '{}' is empty", filename);
return proc_exit::Code::DATA_ERR.to_result();
}
println!("Processing file content...");
println!("First 100 chars: {}", &content[..content.len().min(100)]);
// 模拟处理过程
if content.contains("error") {
eprintln!("Error: File contains 'error' keyword");
return proc_exit::Code::DATA_ERR.to_result();
}
// 模拟成功处理
println!("File processed successfully");
Ok(())
}
fn main() -> proc_exit::ExitResult {
let args: Vec<String> = std::env::args().collect();
// 参数检查
if args.len() != 2 {
eprintln!("Usage: {} <filename>", args[0]);
return proc_exit::Code::USAGE.to_result();
}
let filename = &args[1];
// 检查文件
check_file(filename)?;
// 处理文件
process_file(filename)?;
// 成功退出
proc_exit::Code::SUCCESS.to_result()
}
相关库
其他可能对测试命令行程序有用的库:
duct
用于协调多个进程commandspec
用于更容易地编写命令rexpect
用于控制交互式程序assert_cmd
可以重用以简化控制CLI
许可证
根据以下任一许可证授权:
- Apache License, Version 2.0
- MIT license
由你选择。
1 回复
Rust进程控制库proc-exit的使用:安全终止程序与自定义退出码管理
proc-exit
是一个轻量级的Rust库,专门用于安全地终止程序并管理退出码。它提供了比直接使用std::process::exit
更安全和灵活的方式来控制程序退出行为。
主要特性
- 提供类型安全的退出码管理
- 支持自定义退出码枚举
- 允许在退出前执行清理操作
- 提供与
anyhow
和eyre
等错误处理库的集成
基本使用方法
首先在Cargo.toml中添加依赖:
[dependencies]
proc-exit = "1.0.0"
简单示例
use proc_exit::prelude::*;
fn main() {
// 成功退出
proc_exit::exit(0);
// 或使用预定义的常量
proc_exit::exit!(proc_exit::Code::SUCCESS);
}
自定义退出码
use proc_exit::prelude::*;
#[derive(Debug)]
enum ExitCode {
Success = 0,
InvalidInput = 1,
IoError = 2,
CalculationError = 3,
}
fn main() {
let result = do_something();
match result {
Ok(_) => proc_exit::exit!(ExitCode::Success),
Err(e) => {
eprintln!("Error: {}", e);
proc_exit::exit!(ExitCode::CalculationError);
}
}
}
fn do_something() -> Result<(), String> {
// 模拟可能失败的操作
if rand::random() {
Ok(())
} else {
Err("Something went wrong".to_string())
}
}
与错误处理库集成
与anyhow集成
use proc_exit::prelude::*;
use anyhow::{Context, Result};
fn main() -> proc_exit::ExitResult {
run().with_code(1)
}
fn run() -> Result<()> {
let config = std::fs::read_to_string("config.toml")
.context("Failed to read config file")?;
// 处理配置...
Ok(())
}
与eyre集成
use proc_exit::prelude::*;
use eyre::{WrapErr, Result};
fn main() -> proc_exit::ExitResult {
run().with_code(1)
}
fn run() -> Result<()> {
let data = std::fs::read("data.bin")
.wrap_err("Could not read data file")?;
// 处理数据...
Ok(())
}
高级用法
退出前执行清理
use proc_exit::prelude::*;
fn main() {
let cleanup = || {
println!("Performing cleanup before exit...");
// 执行清理操作
};
// 注册退出时的清理函数
proc_exit::set_hook(cleanup);
// 现在任何通过proc_exit::exit的退出都会先执行清理
if some_condition() {
proc_exit::exit!(1);
}
}
fn some_condition() -> bool {
true
}
自定义退出处理
use proc_exit::prelude::*;
fn main() {
// 替换默认的退出处理
proc_exit::set_exit(move |code| {
println!("Custom exit handler with code: {}", code);
std::process::exit(code);
});
proc_exit::exit!(0);
}
完整示例代码
下面是一个综合了上述特性的完整示例:
use proc_exit::prelude::*;
use anyhow::{Context, Result};
// 自定义退出码枚举
#[derive(Debug)]
enum AppExitCode {
Success = 0,
ConfigError = 1,
DataError = 2,
RuntimeError = 3,
}
fn main() -> proc_exit::ExitResult {
// 设置退出前的清理函数
proc_exit::set_hook(|| {
println!("执行清理操作:关闭文件、释放资源等...");
});
// 主程序逻辑
run().map_err(|e| {
eprintln!("应用程序错误: {}", e);
// 根据错误类型返回不同的退出码
if e.to_string().contains("配置文件") {
proc_exit::Code::from(AppExitCode::ConfigError)
} else if e.to_string().contains("数据") {
proc_exit::Code::from(AppExitCode::DataError)
} else {
proc_exit::Code::from(AppExitCode::RuntimeError)
}
})
}
fn run() -> Result<()> {
// 模拟读取配置文件
let config = std::fs::read_to_string("config.toml")
.context("无法读取配置文件")?;
// 模拟处理数据
let data = std::fs::read("data.bin")
.context("无法读取数据文件")?;
// 模拟业务逻辑
if rand::random() {
Ok(())
} else {
Err(anyhow::anyhow!("随机运行时错误"))
}
}
这个完整示例展示了:
- 自定义退出码枚举
- 退出前的清理操作
- 与anyhow错误处理集成
- 根据错误类型返回不同的退出码
- 类型安全的退出码管理
为什么使用proc-exit而不是std::process::exit
- 类型安全:
proc-exit
提供了类型安全的退出码管理 - 灵活性:支持自定义退出码枚举
- 可扩展性:可以注册退出前的钩子函数
- 集成性:与流行的错误处理库无缝集成
- 测试友好:更容易在测试中模拟退出行为
proc-exit
是构建需要精细控制退出行为的命令行工具的绝佳选择,特别是当你的程序需要以不同的状态码退出,或者在退出前需要执行清理操作时。