gh_docs_download/
error.rs

1//! Error types for the GitHub documentation downloader.
2//!
3//! This module provides comprehensive error handling with semantic error types
4//! that clearly indicate what went wrong and provide actionable information.
5
6use thiserror::Error;
7
8/// Result type alias for GitHub documentation operations.
9pub type Result<T> = std::result::Result<T, GitHubDocsError>;
10
11/// Comprehensive error type for GitHub documentation operations.
12///
13/// This error type provides specific variants for different failure modes,
14/// making it easier to handle errors appropriately and provide useful
15/// feedback to users.
16#[derive(Debug, Error)]
17pub enum GitHubDocsError {
18    /// Invalid repository format provided
19    #[error("Invalid repository format: {input}. Expected format: 'owner/repo' or 'https://github.com/owner/repo'")]
20    InvalidRepoFormat {
21        /// The invalid input that was provided
22        input: String,
23    },
24
25    /// Repository not found or access denied
26    #[error("Repository '{owner}/{repo}' not found or access denied")]
27    RepositoryNotFound {
28        /// Repository owner name
29        owner: String,
30        /// Repository name
31        repo: String,
32    },
33
34    /// No documentation directories found
35    #[error("No documentation directories found in repository '{owner}/{repo}'")]
36    NoDocumentationFound {
37        /// Repository owner name
38        owner: String,
39        /// Repository name
40        repo: String,
41    },
42
43    /// File download failed
44    #[error("Failed to download file '{path}': {reason}")]
45    DownloadFailed {
46        /// Path of the file that failed to download
47        path: String,
48        /// Reason for the download failure
49        reason: String,
50    },
51
52    /// Git operation failed
53    #[error("Git operation failed: {command} - {stderr}")]
54    GitOperationFailed {
55        /// Git command that failed
56        command: String,
57        /// Standard error output from the git command
58        stderr: String,
59    },
60
61    /// Invalid URL provided
62    #[error("Invalid URL: {url}")]
63    InvalidUrl {
64        /// The invalid URL that was provided
65        url: String,
66    },
67
68    /// File system operation failed
69    #[error("File system operation failed")]
70    FileSystemError(#[from] std::io::Error),
71
72    /// URL parsing failed
73    #[error("URL parsing failed")]
74    UrlParseError(#[from] url::ParseError),
75
76    /// Path manipulation failed
77    #[error("Path manipulation failed")]
78    PathError(#[from] std::path::StripPrefixError),
79
80    /// `WalkDir` error
81    #[error("Directory traversal failed")]
82    WalkDirError(#[from] walkdir::Error),
83
84    /// Repository owner validation error
85    #[error("Repository owner validation failed")]
86    RepoOwnerValidationError(#[from] RepoOwnerError),
87
88    /// Repository name validation error
89    #[error("Repository name validation failed")]
90    RepoNameValidationError(#[from] RepoNameError),
91}
92
93impl GitHubDocsError {
94    /// Create a repository not found error.
95    pub fn repository_not_found(owner: impl Into<String>, repo: impl Into<String>) -> Self {
96        Self::RepositoryNotFound {
97            owner: owner.into(),
98            repo: repo.into(),
99        }
100    }
101
102    /// Create a no documentation found error.
103    pub fn no_documentation_found(owner: impl Into<String>, repo: impl Into<String>) -> Self {
104        Self::NoDocumentationFound {
105            owner: owner.into(),
106            repo: repo.into(),
107        }
108    }
109
110    /// Create a download failed error.
111    pub fn download_failed(path: impl Into<String>, reason: impl Into<String>) -> Self {
112        Self::DownloadFailed {
113            path: path.into(),
114            reason: reason.into(),
115        }
116    }
117
118    /// Create a git operation failed error.
119    pub fn git_operation_failed(command: impl Into<String>, stderr: impl Into<String>) -> Self {
120        Self::GitOperationFailed {
121            command: command.into(),
122            stderr: stderr.into(),
123        }
124    }
125}
126
127/// Error type for repository owner validation.
128#[derive(Debug, Error)]
129pub enum RepoOwnerError {
130    /// Repository owner name is empty
131    #[error("Repository owner cannot be empty")]
132    Empty,
133    /// Repository owner contains invalid characters
134    #[error("Repository owner contains invalid characters: {owner}")]
135    InvalidCharacters {
136        /// The invalid owner name that was provided
137        owner: String,
138    },
139    /// Repository owner name exceeds maximum length
140    #[error("Repository owner is too long: {len} characters (max 39)")]
141    TooLong {
142        /// The actual length of the provided owner name
143        len: usize,
144    },
145}
146
147/// Error type for repository name validation.
148#[derive(Debug, Error)]
149pub enum RepoNameError {
150    /// Repository name is empty
151    #[error("Repository name cannot be empty")]
152    Empty,
153    /// Repository name contains invalid characters
154    #[error("Repository name contains invalid characters: {name}")]
155    InvalidCharacters {
156        /// The invalid repository name that was provided
157        name: String,
158    },
159    /// Repository name exceeds maximum length
160    #[error("Repository name is too long: {len} characters (max 100)")]
161    TooLong {
162        /// The actual length of the provided repository name
163        len: usize,
164    },
165}