libmake/
args.rs

1// Copyright notice and licensing information.
2// These lines indicate the copyright of the software and its licensing terms.
3// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses.
4// Copyright © 2023-2024 LibMake. All rights reserved.
5
6use super::{
7    extract_param, generate_file, generator::generate_files,
8    generators::csv::generate_from_csv,
9    generators::ini::generate_from_ini,
10    generators::json::generate_from_json,
11    generators::toml::generate_from_toml,
12    generators::yaml::generate_from_yaml,
13    models::model_params::FileGenerationParams,
14};
15use clap::ArgMatches;
16use regex::Regex;
17use std::error::Error;
18
19/// Processes the command line arguments provided to the program.
20///
21/// This function takes in command-line arguments parsed by `clap` and performs actions based on the arguments provided.
22///
23/// # Arguments
24///
25/// * `matches` - An instance of `clap::ArgMatches` containing the parsed command line arguments.
26///
27/// # Errors
28///
29/// This function will return an error if there is an issue with processing the command line arguments or generating files.
30pub fn process_arguments(
31    matches: &ArgMatches,
32) -> Result<(), Box<dyn Error>> {
33    match matches.subcommand() {
34        Some(("file", file_matches)) => {
35            if let Some(value) = file_matches.get_one::<String>("csv") {
36                generate_file!("csv", value, generate_from_csv);
37            }
38            if let Some(value) = file_matches.get_one::<String>("ini") {
39                generate_file!("ini", value, generate_from_ini);
40            }
41            if let Some(value) = file_matches.get_one::<String>("json")
42            {
43                generate_file!("json", value, generate_from_json);
44            }
45            if let Some(value) = file_matches.get_one::<String>("yaml")
46            {
47                generate_file!("yaml", value, generate_from_yaml);
48            }
49            if let Some(value) = file_matches.get_one::<String>("toml")
50            {
51                generate_file!("toml", value, generate_from_toml);
52            }
53        }
54        Some(("manual", manual_matches)) => {
55            let params = extract_manual_params(manual_matches)?;
56            if let Err(err) = generate_files(params) {
57                eprintln!("Error generating template files: {}", err);
58            } else {
59                println!("Template files generated successfully!");
60            }
61        }
62        _ => {
63            eprintln!("No valid subcommand was used. Please use '--help' for usage information.");
64        }
65    }
66
67    Ok(())
68}
69
70/// Extracts the parameters for manual generation from command line arguments.
71pub fn extract_manual_params(
72    matches: &ArgMatches,
73) -> Result<FileGenerationParams, Box<dyn Error>> {
74    let params = FileGenerationParams {
75        author: extract_param!(matches, "author"),
76        build: extract_param!(matches, "build"),
77        categories: extract_param!(matches, "categories"),
78        description: extract_param!(matches, "description"),
79        documentation: extract_param!(matches, "documentation"),
80        edition: extract_param!(matches, "edition"),
81        email: extract_param!(matches, "email"),
82        homepage: extract_param!(matches, "homepage"),
83        keywords: extract_param!(matches, "keywords"),
84        license: extract_param!(matches, "license"),
85        name: extract_param!(matches, "name"),
86        output: extract_param!(matches, "output"),
87        readme: extract_param!(matches, "readme"),
88        repository: extract_param!(matches, "repository"),
89        rustversion: extract_param!(matches, "rustversion"),
90        version: extract_param!(matches, "version"),
91        website: extract_param!(matches, "website"),
92    };
93    validate_params(&params)?;
94    Ok(params)
95}
96
97/// Validates the manual generation parameters.
98pub fn validate_params(
99    params: &FileGenerationParams,
100) -> Result<(), Box<dyn Error>> {
101    if params.name.is_none() {
102        return Err("The name of the library is required for manual generation.".into());
103    }
104
105    if params.output.is_none() {
106        return Err(
107            "The output directory is required for manual generation."
108                .into(),
109        );
110    }
111
112    if let Some(edition) = &params.edition {
113        let valid_editions = ["2015", "2018", "2021"];
114        if !valid_editions.contains(&edition.as_str()) {
115            return Err(format!(
116                "Invalid edition: {}. Supported editions are: {}.",
117                edition,
118                valid_editions.join(", ")
119            )
120            .into());
121        }
122    }
123
124    if let Some(rustversion) = &params.rustversion {
125        let version_regex = Regex::new(r"^1\.\d+\.\d+$").unwrap();
126        if !version_regex.is_match(rustversion) {
127            return Err(format!(
128                "Invalid Rust version: {}. Rust version should be in the format '1.x.y'.",
129                rustversion
130            )
131            .into());
132        }
133    }
134
135    if let Some(email) = &params.email {
136        let email_regex = Regex::new(
137            r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$",
138        )
139        .unwrap();
140        if !email_regex.is_match(email) {
141            return Err(
142                format!("Invalid email address: {}.", email).into()
143            );
144        }
145    }
146
147    if let Some(repository) = &params.repository {
148        let repo_regex =
149            Regex::new(r"^(https://|git://|ssh://|git@).+\.git$")
150                .unwrap();
151        if !repo_regex.is_match(repository) {
152            return Err(format!(
153                "Invalid repository URL: {}. Repository URL should be a valid Git URL.",
154                repository
155            )
156            .into());
157        }
158    }
159
160    if let Some(homepage) = &params.homepage {
161        let url_regex = Regex::new(r"^(http://|https://).+$").unwrap();
162        if !url_regex.is_match(homepage) {
163            return Err(format!(
164                "Invalid homepage URL: {}. Homepage URL should start with 'http://' or 'https://'.",
165                homepage
166            )
167            .into());
168        }
169    }
170
171    if let Some(documentation) = &params.documentation {
172        let url_regex = Regex::new(r"^(http://|https://).+$").unwrap();
173        if !url_regex.is_match(documentation) {
174            return Err(format!(
175                "Invalid documentation URL: {}. Documentation URL should start with 'http://' or 'https://'.",
176                documentation
177            )
178            .into());
179        }
180    }
181
182    Ok(())
183}