workhelix_cli_common/
license.rs

1//! License display module.
2//!
3//! This module provides standardized license information display for common open source licenses.
4
5use crate::output;
6
7/// Supported license types.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum LicenseType {
10    /// MIT License
11    MIT,
12    /// Apache License 2.0
13    Apache2,
14    /// Creative Commons CC0 1.0 Universal
15    CC0,
16}
17
18impl LicenseType {
19    /// Parse a license type from a string.
20    ///
21    /// Recognizes common variations like "MIT", "Apache-2.0", "CC0-1.0", etc.
22    #[must_use]
23    pub fn parse(s: &str) -> Option<Self> {
24        match s.to_uppercase().as_str() {
25            "MIT" => Some(Self::MIT),
26            "APACHE-2.0" | "APACHE2" | "APACHE" => Some(Self::Apache2),
27            "CC0-1.0" | "CC0" => Some(Self::CC0),
28            _ => None,
29        }
30    }
31
32    /// Get the license name.
33    #[must_use]
34    pub const fn name(self) -> &'static str {
35        match self {
36            Self::MIT => "MIT",
37            Self::Apache2 => "Apache-2.0",
38            Self::CC0 => "CC0-1.0",
39        }
40    }
41}
42
43/// Display license information for a tool.
44///
45/// # Arguments
46/// * `tool_name` - Name of the tool
47/// * `license` - License type
48///
49/// # Returns
50/// Formatted license information string
51#[must_use]
52pub fn display_license(tool_name: &str, license: LicenseType) -> String {
53    let mut output = format!("{tool_name} is licensed under {}\n\n", license.name());
54
55    match license {
56        LicenseType::MIT => {
57            output.push_str("MIT License - A permissive license that allows:\n");
58            output.push_str("• Commercial use\n");
59            output.push_str("• Modification\n");
60            output.push_str("• Distribution\n");
61            output.push_str("• Private use\n");
62            output.push('\n');
63            output.push_str("Requires:\n");
64            output.push_str("• License and copyright notice\n");
65            output.push('\n');
66            output.push_str("MIT License\n");
67            output.push('\n');
68            output.push_str("Permission is hereby granted, free of charge, to any person obtaining a copy\n");
69            output.push_str("of this software and associated documentation files (the \"Software\"), to deal\n");
70            output.push_str("in the Software without restriction, including without limitation the rights\n");
71            output.push_str("to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n");
72            output.push_str("copies of the Software, and to permit persons to whom the Software is\n");
73            output.push_str("furnished to do so, subject to the following conditions:\n");
74            output.push('\n');
75            output.push_str("The above copyright notice and this permission notice shall be included in all\n");
76            output.push_str("copies or substantial portions of the Software.\n");
77            output.push('\n');
78            output.push_str("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n");
79            output.push_str("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n");
80            output.push_str("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n");
81            output.push_str("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n");
82            output.push_str("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n");
83            output.push_str("OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n");
84            output.push_str("SOFTWARE.\n");
85        }
86        LicenseType::Apache2 => {
87            output.push_str("Apache License 2.0 - A permissive license that allows:\n");
88            output.push_str("• Commercial use\n");
89            output.push_str("• Modification\n");
90            output.push_str("• Distribution\n");
91            output.push_str("• Patent use\n");
92            output.push_str("• Private use\n");
93            output.push('\n');
94            output.push_str("Requires:\n");
95            output.push_str("• License and copyright notice\n");
96            output.push_str("• State changes\n");
97        }
98        LicenseType::CC0 => {
99            output.push_str("Creative Commons CC0 1.0 Universal - Public domain dedication:\n");
100            output.push_str("• No rights reserved\n");
101            output.push_str("• Can be used for any purpose\n");
102            output.push_str("• No attribution required\n");
103        }
104    }
105
106    output.push('\n');
107
108    if output::is_tty() {
109        use colored::Colorize;
110        use std::fmt::Write;
111        writeln!(output, "For full license text, see: {}", "LICENSE file in project root".blue().underline()).unwrap();
112    } else {
113        output.push_str("For full license text, see: LICENSE file in project root\n");
114    }
115
116    output
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_license_type_from_str() {
125        assert_eq!(LicenseType::parse("MIT"), Some(LicenseType::MIT));
126        assert_eq!(LicenseType::parse("mit"), Some(LicenseType::MIT));
127        assert_eq!(LicenseType::parse("Apache-2.0"), Some(LicenseType::Apache2));
128        assert_eq!(LicenseType::parse("apache"), Some(LicenseType::Apache2));
129        assert_eq!(LicenseType::parse("CC0-1.0"), Some(LicenseType::CC0));
130        assert_eq!(LicenseType::parse("cc0"), Some(LicenseType::CC0));
131        assert_eq!(LicenseType::parse("unknown"), None);
132    }
133
134    #[test]
135    fn test_license_type_name() {
136        assert_eq!(LicenseType::MIT.name(), "MIT");
137        assert_eq!(LicenseType::Apache2.name(), "Apache-2.0");
138        assert_eq!(LicenseType::CC0.name(), "CC0-1.0");
139    }
140
141    #[test]
142    fn test_display_license_mit() {
143        let output = display_license("test-tool", LicenseType::MIT);
144        assert!(output.contains("test-tool"));
145        assert!(output.contains("MIT"));
146        assert!(output.contains("Permission is hereby granted"));
147        assert!(output.contains("Commercial use"));
148    }
149
150    #[test]
151    fn test_display_license_apache() {
152        let output = display_license("test-tool", LicenseType::Apache2);
153        assert!(output.contains("test-tool"));
154        assert!(output.contains("Apache"));
155        assert!(output.contains("Patent use"));
156    }
157
158    #[test]
159    fn test_display_license_cc0() {
160        let output = display_license("test-tool", LicenseType::CC0);
161        assert!(output.contains("test-tool"));
162        assert!(output.contains("CC0"));
163        assert!(output.contains("No rights reserved"));
164    }
165}