sccmod 0.6.4

A mediocre module manager for handling multiple versions of self-compiled modules
Documentation
use crate::{
    config,
    module::{Dependency, Environment, Module},
};

#[must_use]
pub fn generate(module: &Module) -> String {
    // Generate a modulefile with support for flavours
    // The modulefile has the following format:

    let config = config::read().unwrap();

    let module_class = &module.class;

    let module_conflict =
        if config.class_no_conflict.contains(&module_class.to_string()) {
            String::new()
        } else {
            format!("::flavours::conflict -class {module_class}\n")
        };

    let mut module_metadata_str = String::new();
    for (key, value) in &module.metadata {
        module_metadata_str.push_str(&format!("# {key}: {value}\n"));
    }

    let mut module_metadata_str_no_hashes = String::new();
    for (key, value) in &module.metadata {
        module_metadata_str_no_hashes.push_str(&format!("{key}: {value}\n"));
    }

    let no_description_provided = "No description provided".to_string();
    let module_description =
        module.metadata.get("description").unwrap_or(&no_description_provided);

    let dependent_modules = module
        .dependencies
        .iter()
        .filter_map(|dep| {
            if let Dependency::Depends(name) = dep {
                Some(format!("depends-on {}\n", name))
            } else {
                None
            }
        })
        .fold(String::new(), |mut acc, dep| {
            acc.push_str(&dep);
            acc
        });

    let mut class_definitions = String::new();
    for class in module.dependencies.iter().filter_map(|dep| {
        if let Dependency::Class(name) = dep {
            Some(name)
        } else {
            None
        }
    }) {
        class_definitions
            .push_str(&format!("::flavours::prereq -class {class}\n"));
    }

    let root_dir = &module.install_path;

    let mut environment_variables = String::new();
    for (key, value) in &module.environment {
        environment_variables.push_str(&match value {
            // Environment::Set(val) => format!("setenv \"{key}\" \"{val}\"\n"),
            Environment::Set(val) => format!("::flavours::modify-path setenv \"{key}\" \"{val}\"\n"),
            Environment::SetExact(val) => format!(" setenv \"{key}\" \"{val}\"\n"),
            Environment::Append(val) => format!("::flavours::append-path \"{key}\" \"{val}\"\n"),
            Environment::Prepend(val) => {
                format!("::flavours::modify-path prepend-path \"{key}\" \"{val}\"\n")
            }
        });
    }

    format!(
        r#"#%Module
# MODULEFILE GENERATED BY SCCMOD
# https://github.com/Pencilcaseman/sccmod

package require flavours 

# Flavours is a bit of a pain, so we have to redefine it sometimes.
# Don't ask me why.
if {{![info exists flavours] || [info procs flavours] eq ""}} {{
    proc flavours {{comm args}} {{
        # "whatis" is fragile: don't do anything!
        if {{ [module-info mode whatis] }} {{ return }}
        if {{ [module-info mode help]  }} {{ return }}

        # Switchboard
        switch $comm {{
            append-path  -
            prepend-path -
            remove-path  {{ eval ::flavours::modify-path $comm $args }}
            get          {{ eval ::flavours::get_$args }}
            default      {{ eval ::flavours::$comm $args }}
        }}
    }}

    # Uncomment this for debug information.
    # puts stderr "Redefined flavours procedure"
}}

flavours init

# Metadata
{module_metadata_str}

# Module help
proc ModulesHelp {{ }} {{
   puts stderr "
{module_metadata_str_no_hashes}
"
}}

module-whatis "{module_description}"

# Load submodules
{dependent_modules}

# Module prerequisites
{class_definitions}

# Conflict with other modules of the same class
# ::flavours::conflict -class {module_class}
{module_conflict}

# Evaluate the flavour
::flavours::root     {root_dir}
::flavours::revision 1
::flavours::commit

# Set environment variables
{environment_variables}

# Cleanup and reload conflicting modules
::flavours::cleanup
"#
    )
}