41 个版本 (6 个破坏性更新)
0.8.2 | 2024年7月27日 |
---|---|
0.7.2 | 2024年6月6日 |
0.5.2 | 2024年3月29日 |
0.2.12 | 2023年12月26日 |
0.2.0 | 2023年7月26日 |
#206 在 开发工具
每月下载 2,569 次
用于 2 crates
38KB
739 行
starbase
构建高性能命令行应用程序和开发者工具的应用程序框架。
用法
应用程序使用基于会话的方法,其中会话对象包含整个应用程序生命周期所需的数据。
创建一个 App
,可选地设置诊断 (miette
) 和跟踪 (tracing
),然后使用提供的会话运行应用程序。需要可变会话,因为会话可以在每个 阶段 中被修改。
use starbase::{App, MainResult};
use crate::CustomSession;
#[tokio::main]
async fn main() -> MainResult {
let app = App::default();
app.setup_diagnostics();
let mut session = CustomSession::default();
app.run(&mut session, |session| async {
// Run CLI
Ok(())
}).await?;
Ok(())
}
会话
会话必须实现 AppSession
特性。这个特性提供了 4 个可选方法,每个方法代表应用程序生命周期中的不同 阶段。
use starbase::{AppSession, AppResult};
use std::path::PathBuf;
use async_trait::async_trait;
#[derive(Clone)]
pub struct CustomSession {
pub workspace_root: PathBuf,
}
#[async_trait]
impl AppSession for CustomSession {
async fn startup(&mut self) -> AppResult {
self.workspace_root = detect_workspace_root()?;
Ok(())
}
}
会话 必须 可克隆 并且 与
Send + Sync
兼容。我们在创建 tokio 任务时克隆会话。如果您想跨线程持久化数据,请使用Arc
、RwLock
和其他机制包装会话属性。
阶段
应用程序被划分为阶段,其中每个阶段将在进入下一个阶段之前被处理和完成。以下阶段可用:
- 启动 - 注册、设置或加载初始会话状态。
- 示例:加载配置、检测工作区根目录、加载插件
- 分析 - 分析当前环境,更新状态,并准备执行。
- 示例:生成项目图、加载缓存、登录服务
- 执行 - 执行主要业务逻辑 (
App#run
)。- 示例:处理依赖图、运行生成器、检查新版本
- 关闭 - 在整个生命周期的成功完成时或特定阶段失败时进行清理和关闭。
- 示例:清理临时文件,关闭服务器
如果一个会话实现了
AppSession#execute
特性方法,它将与App#run
方法并行运行。
如何
错误处理
错误和诊断由 miette
包提供。应用程序的所有层都返回 miette::Result
类型(通过 AppResult
)。这使得错误可以轻松转换为诊断,并且 miette 可以自动将错误和恐慌渲染到终端。
要利用这一点,请更新您的 main
函数以返回 MainResult
。
use starbase::{App, MainResult};
#[tokio::main]
async fn main() -> MainResult {
let app = App::default();
app.setup_diagnostics();
app.setup_tracing_defaults();
// ...
Ok(())
}
为了最大限度地利用错误和诊断,最好(也是建议)使用 thiserror
包。
use miette::Diagnostic;
use thiserror::Error;
#[derive(Debug, Diagnostic, Error)]
pub enum AppError {
#[error(transparent)]
#[diagnostic(code(app::io_error))]
IoError(#[from] std::io::Error),
#[error("Systems offline!")]
#[diagnostic(code(app::bad_code))]
SystemsOffline,
}
注意事项
返回的 Err
必须首先转换为诊断。有两种方法可以实现这一点
#[system]
async fn could_fail() {
// Convert error using into()
Err(AppError::SystemsOffline.into())
// OR use ? operator on Err()
Err(AppError::SystemsOffline)?
}
依赖关系
~7–18MB
~227K SLoC