Files
empeve/src/error.rs
vikingowl 6f714e58fa Implement comprehensive improvement roadmap (Phases 0-4)
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>
2025-12-15 03:44:37 +01:00

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>;