update_available/lib.rs
1use crate::data::{UpdateAvailable, UpdateInfo};
2
3mod data;
4mod logic;
5
6#[cfg(test)]
7mod test;
8
9/// A user identifier for GitHub repositories.
10type User = String;
11
12/// Represents the source from which to check for updates.
13pub enum Source {
14 /// Check for updates on crates.io.
15 CratesIo,
16 /// Check for updates on GitHub for a specific user.
17 Github(User),
18 /// Check for updates on Gitea for a specific user and Gitea URL.
19 Gitea(User, String),
20}
21
22/// Prints update information for a package from the specified source.
23///
24/// This is a convenience function that checks for updates and prints the result
25/// directly to stdout even if no update is available. To show the user
26/// the current status of the package, including whether an update is available.
27///
28/// # Arguments
29///
30/// * `name` - The name of the package to check
31/// * `current_version` - The current version string (e.g., "1.0.0")
32/// * `source` - The source to check for updates
33///
34/// # Examples
35///
36/// ```rust
37/// use update_available::{print_check_force, Source};
38///
39/// // Check crates.io
40/// print_check_force("serde", "1.0.0", Source::CratesIo);
41///
42/// // Check GitHub
43/// print_check_force("my-repo", "0.1.0", Source::Github("username".to_string()));
44///
45/// // Check Gitea
46/// print_check_force("my-repo", "0.1.0", Source::Gitea("username".to_string(), "https://gitea.example.com".to_string()));
47/// ```
48pub fn print_check_force(name: &str, current_version: &str, source: Source) {
49 print_check_internal(name, current_version, source, true);
50}
51
52/// Prints update information for a package from the specified source.
53///
54/// This is a convenience function that checks for updates and prints the result
55/// directly to stdout if an update is available.
56///
57/// # Arguments
58///
59/// * `name` - The name of the package to check
60/// * `current_version` - The current version string (e.g., "1.0.0")
61/// * `source` - The source to check for updates
62///
63/// # Examples
64///
65/// ```rust
66/// use update_available::{print_check, Source};
67///
68/// // Check crates.io
69/// print_check("serde", "1.0.0", Source::CratesIo);
70///
71/// // Check GitHub
72/// print_check("my-repo", "0.1.0", Source::Github("username".to_string()));
73///
74/// // Check Gitea
75/// print_check("my-repo", "0.1.0", Source::Gitea("username".to_string(), "https://gitea.example.com".to_string()));
76/// ```
77pub fn print_check(name: &str, current_version: &str, source: Source) {
78 print_check_internal(name, current_version, source, false);
79}
80
81/// Prints update information for a package from the specified source.
82///
83/// This is a convenience function that checks for updates and prints the result
84/// directly to stdout if an update is available.
85///
86/// # Arguments
87///
88/// * `name` - The name of the package to check
89/// * `current_version` - The current version string (e.g., "1.0.0")
90/// * `source` - The source to check for updates
91fn print_check_internal(name: &str, current_version: &str, source: Source, always_print: bool) {
92 let result = match source {
93 Source::CratesIo => check_crates_io(name, current_version),
94 Source::Github(user) => check_github(name, &user, current_version),
95 Source::Gitea(user, gitea_url) => check_gitea(name, &user, &gitea_url, current_version),
96 };
97 match result {
98 Ok(info) if info.is_update_available => info.print(),
99 Ok(_) if always_print => println!("No updates available for {name}@{current_version}"),
100 Err(e) if always_print => eprintln!("Error checking for updates: {e}"),
101 _ => {}
102 }
103}
104
105/// Checks for updates on crates.io for the specified package.
106///
107/// This function queries the crates.io API to check if a newer version
108/// of the specified package is available.
109///
110/// # Arguments
111///
112/// * `name` - The name of the crate to check on crates.io
113/// * `current_version` - The current version string (e.g., "1.0.0")
114///
115/// # Returns
116///
117/// Returns a `Result<UpdateInfo, anyhow::Error>` containing update information
118/// if successful, or an error if the check fails.
119///
120/// # Errors
121///
122/// This function will return an error if:
123/// * The network request fails
124/// * The crates.io API returns an error
125/// * The version strings cannot be parsed
126/// * The response format is unexpected
127///
128/// # Examples
129///
130/// ```ignore
131/// use update_available::check_crates_io;
132///
133/// match check_crates_io("serde", "1.0.0") {
134/// Ok(info) => println!("{}", info),
135/// Err(e) => eprintln!("Error checking for updates: {}", e),
136/// }
137/// ```
138fn check_crates_io(name: &str, current_version: &str) -> anyhow::Result<UpdateInfo> {
139 let update_available = UpdateAvailable::new(name, current_version);
140 update_available.crates_io()
141}
142
143/// Checks for updates on GitHub for the specified repository.
144///
145/// This function queries the GitHub API to check if a newer version
146/// of the specified repository is available.
147///
148/// # Arguments
149///
150/// * `name` - The name of the repository to check
151/// * `user` - The GitHub username or organization that owns the repository
152/// * `current_version` - The current version string (e.g., "1.0.0")
153///
154/// # Returns
155///
156/// Returns a `Result<UpdateInfo, anyhow::Error>` containing update information
157/// if successful, or an error if the check fails.
158///
159/// # Errors
160///
161/// This function will return an error if:
162/// * The network request fails
163/// * The GitHub API returns an error
164/// * The version strings cannot be parsed
165/// * The response format is unexpected
166/// * The repository does not exist or has no releases
167///
168/// # Examples
169///
170/// ```ignore
171/// use update_available::check_github;
172///
173/// match check_github("my-repo", "username", "1.0.0") {
174/// Ok(info) => println!("{}", info),
175/// Err(e) => eprintln!("Error checking for updates: {}", e),
176/// }
177/// ```
178fn check_github(name: &str, user: &str, current_version: &str) -> anyhow::Result<UpdateInfo> {
179 let update_available = UpdateAvailable::new(name, current_version);
180 update_available.github(user)
181}
182
183/// Checks for updates on Gitea for the specified repository.
184///
185/// This function queries the Gitea API to check if a newer version
186/// of the specified repository is available.
187///
188/// # Arguments
189///
190/// * `name` - The name of the repository to check
191/// * `user` - The Gitea username or organization that owns the repository
192/// * `gitea_url` - The base URL of the Gitea instance (e.g., <https://gitea.example.com>)
193/// * `current_version` - The current version string (e.g., "1.0.0")
194///
195/// # Returns
196///
197/// Returns a `Result<UpdateInfo, anyhow::Error>` containing update information
198/// if successful, or an error if the check fails.
199///
200/// # Errors
201///
202/// This function will return an error if:
203/// * The network request fails
204/// * The Gitea API returns an error
205/// * The version strings cannot be parsed
206/// * The response format is unexpected
207/// * The repository does not exist or has no releases
208///
209/// # Examples
210///
211/// ```ignore
212/// use update_available::check_gitea;
213///
214/// match check_gitea("my-repo", "username", "https://gitea.example.com", "1.0.0") {
215/// Ok(info) => println!("{}", info),
216/// Err(e) => eprintln!("Error checking for updates: {}", e),
217/// }
218/// ```
219fn check_gitea(
220 name: &str,
221 user: &str,
222 gitea_url: &str,
223 current_version: &str,
224) -> anyhow::Result<UpdateInfo> {
225 let update_available = UpdateAvailable::new(name, current_version);
226 update_available.gitea(user, gitea_url)
227}