ipfrs_cli/
utils.rs

1//! Utility functions for CLI maintenance and distribution
2//!
3//! This module provides utilities for:
4//! - Man page generation
5//! - Auto-update checking
6//! - Version management
7
8use anyhow::{Context, Result};
9use std::path::Path;
10
11/// Current version of the CLI
12pub const VERSION: &str = env!("CARGO_PKG_VERSION");
13
14/// Repository URL for checking updates
15pub const REPO_URL: &str = "https://github.com/tensorlogic/ipfrs";
16
17/// Generate man pages for all commands
18///
19/// This function generates comprehensive man pages using clap_mangen.
20/// The man pages are written to the specified output directory.
21///
22/// # Arguments
23///
24/// * `cmd` - The clap::Command structure to generate man pages for
25/// * `out_dir` - Directory where man pages will be written
26///
27/// # Examples
28///
29/// ```no_run
30/// use ipfrs_cli::{build_cli, utils::generate_man_pages};
31/// use std::path::Path;
32///
33/// let cmd = build_cli();
34/// let out_dir = Path::new("target/man");
35/// generate_man_pages(&cmd, out_dir).expect("Failed to generate man pages");
36/// ```
37#[allow(dead_code)]
38pub fn generate_man_pages(cmd: &clap::Command, out_dir: &Path) -> Result<()> {
39    use clap_mangen::Man;
40    use std::fs;
41
42    // Ensure output directory exists
43    fs::create_dir_all(out_dir).context("Failed to create output directory")?;
44
45    // Generate main man page
46    let man = Man::new(cmd.clone());
47    let mut buffer = Vec::new();
48    man.render(&mut buffer)
49        .context("Failed to render main man page")?;
50
51    let main_path = out_dir.join("ipfrs.1");
52    fs::write(&main_path, buffer).context("Failed to write main man page")?;
53
54    println!("Generated: {}", main_path.display());
55
56    // Generate man pages for each subcommand
57    for subcommand in cmd.get_subcommands() {
58        let name = subcommand.get_name();
59        let man = Man::new(subcommand.clone());
60        let mut buffer = Vec::new();
61        man.render(&mut buffer)
62            .with_context(|| format!("Failed to render man page for {}", name))?;
63
64        let path = out_dir.join(format!("ipfrs-{}.1", name));
65        fs::write(&path, buffer)
66            .with_context(|| format!("Failed to write man page for {}", name))?;
67
68        println!("Generated: {}", path.display());
69    }
70
71    Ok(())
72}
73
74/// Check for available updates
75///
76/// This function checks if a newer version is available by querying
77/// the GitHub releases API.
78///
79/// # Returns
80///
81/// Returns `Some(version)` if an update is available, `None` otherwise.
82///
83/// # Examples
84///
85/// ```no_run
86/// use ipfrs_cli::utils::check_for_updates;
87///
88/// # async fn example() {
89/// match check_for_updates().await {
90///     Ok(Some(version)) => println!("Update available: {}", version),
91///     Ok(None) => println!("Up to date"),
92///     Err(e) => eprintln!("Failed to check for updates: {}", e),
93/// }
94/// # }
95/// ```
96pub async fn check_for_updates() -> Result<Option<String>> {
97    // For now, this is a placeholder implementation
98    // In a real implementation, this would query GitHub API or similar
99    Ok(None)
100}
101
102/// Compare two semantic versions
103///
104/// Returns true if `new_version` is newer than `current_version`.
105#[allow(dead_code)]
106fn is_newer_version(current_version: &str, new_version: &str) -> bool {
107    // Simple string comparison for now
108    // In production, use a proper semver crate
109    current_version < new_version
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    #[allow(clippy::len_zero)]
118    fn test_version_constant() {
119        // VERSION is a non-empty constant from CARGO_PKG_VERSION
120        assert!(VERSION.len() > 0);
121        assert!(VERSION.contains('.'));
122    }
123
124    #[test]
125    fn test_repo_url() {
126        assert!(REPO_URL.starts_with("https://"));
127    }
128
129    #[test]
130    fn test_is_newer_version() {
131        assert!(is_newer_version("0.1.0", "0.2.0"));
132        assert!(is_newer_version("0.1.0", "1.0.0"));
133        assert!(!is_newer_version("0.2.0", "0.1.0"));
134        assert!(!is_newer_version("1.0.0", "1.0.0"));
135    }
136}