use std::io::Write;
use colored::Colorize;
use crate::{
config, log,
module::{self, get_modules, Module},
module_resolver,
};
pub fn resolver_boilerplate(
partials: &[&str],
func: fn(&Module) -> Result<(), String>,
) -> Result<(), String> {
match module_resolver::resolve(partials)? {
module_resolver::ResolveMatch::Full(m) => func(&m),
module_resolver::ResolveMatch::Partial(m) => {
let mut err = String::from(
"Multiple modules match the provided partial(s):\n",
);
#[allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss
)]
let max_digits = (m.len() as f64).log10() as usize;
err.push_str(&format!(
"{} {}\n",
String::from(" ").repeat(max_digits),
"all".bold().magenta()
));
for (index, item) in m.iter().enumerate() {
#[allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss
)]
let digits = (index as f64 + 0.05).log10() as usize;
let mut index_str =
String::from(" ").repeat(max_digits - digits);
index_str.push_str(&format!("{index}"));
err.push_str(&format!(
" {index_str}: {}\n",
item.identifier().bold().cyan()
));
}
log::warn(&err);
let mut valid = false;
let mut all = false;
let mut selection = String::new();
let mut selection_index = 0;
while !valid && !all {
print!("{}", "Please enter a selection: ".yellow().bold());
std::io::stdout().flush().map_err(|e| e.to_string())?;
match std::io::stdin().read_line(&mut selection) {
Ok(_) if selection.trim() == "all" => all = true,
Ok(_) => match selection.trim().parse::<usize>() {
Ok(num) if num < m.len() => {
valid = true;
selection_index = num;
}
Ok(_) => {
log::warn("Invalid index selected");
}
Err(_) => {
log::warn("Invalid input received. Input must be a positive integer or 'all'");
}
},
Err(_) => {
log::warn("Failed to read input");
}
}
selection.clear(); }
if all {
for module in &m {
func(module)?;
}
Ok(())
} else {
func(&m[selection_index])
}
}
module_resolver::ResolveMatch::None => {
log::error("No modules match the partials provided");
}
module_resolver::ResolveMatch::All(m) => {
for module in &m {
func(module)?;
}
Ok(())
}
}
}
pub fn info(config: &config::Config) -> Result<(), String> {
fn fmt<T: std::fmt::Debug>(name: &str, value: &T) {
println!("{} {}", name.bold().purple(), format!("{value:?}").cyan());
}
fmt("config file . . . . :", &std::env::var("SCCMOD_CONFIG"));
fmt("sccmod_module_paths :", &config.sccmod_module_paths);
fmt("modulefile root . . :", &config.modulefile_root);
fmt("build_root . . . . :", &config.build_root);
fmt("install_root . . . :", &config.install_root);
fmt("shell . . . . . . . :", &config.shell);
fmt("num_threads . . . . :", &config.num_threads);
Ok(())
}
pub fn list_callback(_config: &config::Config) -> Result<(), String> {
println!("{}", "Available Modules:".bold().purple());
for p in &get_modules()? {
println!(" > {}", p.identifier().bold().cyan());
}
Ok(())
}
pub fn download_module(
partials: &[&str],
_config: &config::Config,
) -> Result<(), String> {
resolver_boilerplate(partials, module::download)
}
pub fn download_all(_config: &config::Config) -> Result<(), String> {
for m in &get_modules()? {
module::download(m)?;
}
Ok(())
}
pub fn build_module(
partials: &[&str],
_config: &config::Config,
) -> Result<(), String> {
resolver_boilerplate(partials, module::build)
}
pub fn build_all(_config: &config::Config) -> Result<(), String> {
for m in &get_modules()? {
module::build(m)?;
}
Ok(())
}
pub fn install_module(
partials: &[&str],
_config: &config::Config,
) -> Result<(), String> {
resolver_boilerplate(partials, module::install)
}
pub fn write_modulefile(
partials: &[&str],
_config: &config::Config,
) -> Result<(), String> {
resolver_boilerplate(partials, module::modulefile)
}
pub fn install_all(_config: &config::Config) -> Result<(), String> {
for m in &get_modules()? {
module::install(m)?;
}
Ok(())
}
pub fn write_modulefile_all(_config: &config::Config) -> Result<(), String> {
for m in &get_modules()? {
module::modulefile(m)?;
}
Ok(())
}