Phase 0 - Quick fixes:
- Fix catalog entries() return type (removed extra indirection)
- Fix welcome string (mpv-mgr → empeve)
- Fix HEAD detachment on update (branch-aware fast-forward)
- Add fetch_rev with branch detection
Phase 1 - Git model ("rev means rev"):
- Add RevType enum (Commit/Tag/Branch/Default)
- Add UpdateResult enum for update outcomes
- Implement clone_with_rev for proper revision checkout
- Pinned repos (commits/tags) skip auto-update
Phase 2 - Discovery & install fidelity:
- Support init.lua and named entry points for multi-file scripts
- Better asset mapping with prefix matching for configs
- Proactive target directory creation
Phase 3 - UX and quality-of-life:
- Add --verbose flag to status command
- Add 'empeve doctor' diagnostic command
- Improve error messages with actionable hints
Phase 4 - Feature expansion:
- External TOML catalog system (extensible)
- Import --convert-local for local script management
- Lockfile support for reproducible installations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
109 lines
3.8 KiB
Rust
109 lines
3.8 KiB
Rust
use thiserror::Error;
|
|
use git2::{ErrorClass, ErrorCode};
|
|
|
|
/// Detailed git error with actionable hint
|
|
#[derive(Debug)]
|
|
pub struct GitDetailedError {
|
|
pub code: ErrorCode,
|
|
pub class: ErrorClass,
|
|
pub message: String,
|
|
pub hint: String,
|
|
}
|
|
|
|
impl std::fmt::Display for GitDetailedError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.message)
|
|
}
|
|
}
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum EmpveError {
|
|
#[error("Config error: {0}")]
|
|
Config(String),
|
|
|
|
#[error("Git error: {0}")]
|
|
Git(#[from] git2::Error),
|
|
|
|
#[error("IO error: {0}")]
|
|
Io(#[from] std::io::Error),
|
|
|
|
#[error("TOML parse error: {0}")]
|
|
TomlParse(#[from] toml::de::Error),
|
|
|
|
#[error("TOML serialize error: {0}")]
|
|
TomlSerialize(#[from] toml::ser::Error),
|
|
|
|
#[error("Repository not found: {0}")]
|
|
RepoNotFound(String),
|
|
|
|
#[error("Repository already exists: {0}")]
|
|
RepoExists(String),
|
|
|
|
#[error("Script not found: {0}")]
|
|
ScriptNotFound(String),
|
|
|
|
#[error("Invalid repository identifier: {0}")]
|
|
InvalidRepo(String),
|
|
}
|
|
|
|
impl EmpveError {
|
|
/// Get a user-friendly hint for resolving this error
|
|
pub fn hint(&self) -> Option<String> {
|
|
match self {
|
|
EmpveError::Git(e) => Some(git_error_hint(e)),
|
|
EmpveError::RepoNotFound(_) => Some("Check the repository name and try again. Use 'empeve browse' to see available scripts.".to_string()),
|
|
EmpveError::RepoExists(_) => Some("Use 'empeve remove' first if you want to replace it.".to_string()),
|
|
EmpveError::ScriptNotFound(_) => Some("Check script name or run 'empeve status' to see available scripts.".to_string()),
|
|
EmpveError::InvalidRepo(_) => Some("Use format 'user/repo' for GitHub or a full git URL.".to_string()),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Generate a user-friendly hint from a git2 error
|
|
pub fn git_error_hint(error: &git2::Error) -> String {
|
|
match (error.code(), error.class()) {
|
|
(ErrorCode::NotFound, ErrorClass::Reference) => {
|
|
"The specified branch or ref was not found. Check if it exists on the remote.".to_string()
|
|
}
|
|
(ErrorCode::NotFound, ErrorClass::Repository) => {
|
|
"Repository not found. Verify the URL is correct and you have access.".to_string()
|
|
}
|
|
(ErrorCode::Auth, _) => {
|
|
"Authentication failed. The repository may be private or credentials are invalid.".to_string()
|
|
}
|
|
(ErrorCode::Certificate, _) | (_, ErrorClass::Ssl) => {
|
|
"SSL/TLS certificate error. Check your system certificates or network.".to_string()
|
|
}
|
|
(ErrorCode::Locked, _) => {
|
|
"Repository is locked. Another process may be using it. Try again later.".to_string()
|
|
}
|
|
(ErrorCode::Exists, _) => {
|
|
"The destination already exists. Use --force to overwrite.".to_string()
|
|
}
|
|
(ErrorCode::BareRepo, _) => {
|
|
"Cannot perform this operation on a bare repository.".to_string()
|
|
}
|
|
(ErrorCode::UnbornBranch, _) => {
|
|
"The repository has no commits yet.".to_string()
|
|
}
|
|
(ErrorCode::Uncommitted, _) => {
|
|
"There are uncommitted changes. Commit or stash them first.".to_string()
|
|
}
|
|
(_, ErrorClass::Net) | (ErrorCode::GenericError, ErrorClass::Os) => {
|
|
"Network error. Check your internet connection.".to_string()
|
|
}
|
|
(_, ErrorClass::Checkout) => {
|
|
"Checkout failed. There may be conflicting local changes.".to_string()
|
|
}
|
|
(_, ErrorClass::FetchHead) => {
|
|
"Failed to update FETCH_HEAD. Try running 'empeve clean' and reinstalling.".to_string()
|
|
}
|
|
_ => {
|
|
format!("Git operation failed ({:?}/{:?})", error.class(), error.code())
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type Result<T> = std::result::Result<T, EmpveError>;
|