use std::collections::HashMap;
use crate::core::lifecycle::LifecyclePhase;
#[derive(Debug, Clone)]
pub struct PluginBinding {
pub group_id: String,
pub artifact_id: String,
pub version: String,
pub goal: String,
}
impl PluginBinding {
pub fn new(
group_id: impl Into<String>,
artifact_id: impl Into<String>,
version: impl Into<String>,
goal: impl Into<String>,
) -> Self {
Self {
group_id: group_id.into(),
artifact_id: artifact_id.into(),
version: version.into(),
goal: goal.into(),
}
}
pub fn compiler(goal: &str) -> Self {
Self::new("org.apache.maven.plugins", "maven-compiler-plugin", "3.11.0", goal)
}
pub fn resources(goal: &str) -> Self {
Self::new("org.apache.maven.plugins", "maven-resources-plugin", "3.3.1", goal)
}
pub fn surefire(goal: &str) -> Self {
Self::new("org.apache.maven.plugins", "maven-surefire-plugin", "3.1.2", goal)
}
pub fn jar(goal: &str) -> Self {
Self::new("org.apache.maven.plugins", "maven-jar-plugin", "3.3.0", goal)
}
pub fn war(goal: &str) -> Self {
Self::new("org.apache.maven.plugins", "maven-war-plugin", "3.4.0", goal)
}
pub fn install(goal: &str) -> Self {
Self::new("org.apache.maven.plugins", "maven-install-plugin", "3.1.1", goal)
}
pub fn deploy(goal: &str) -> Self {
Self::new("org.apache.maven.plugins", "maven-deploy-plugin", "3.1.1", goal)
}
pub fn plugin_key(&self) -> String {
format!("{}:{}", self.group_id, self.artifact_id)
}
}
#[derive(Debug, Clone, Default)]
pub struct LifecycleMapping {
pub packaging: String,
bindings: HashMap<LifecyclePhase, Vec<PluginBinding>>,
}
impl LifecycleMapping {
pub fn new(packaging: impl Into<String>) -> Self {
Self {
packaging: packaging.into(),
bindings: HashMap::new(),
}
}
pub fn bind(&mut self, phase: LifecyclePhase, binding: PluginBinding) {
self.bindings.entry(phase).or_default().push(binding);
}
pub fn get_bindings(&self, phase: &LifecyclePhase) -> &[PluginBinding] {
self.bindings.get(phase).map(|v| v.as_slice()).unwrap_or(&[])
}
pub fn phases(&self) -> Vec<LifecyclePhase> {
let mut phases: Vec<_> = self.bindings.keys().cloned().collect();
phases.sort_by_key(|p| p.order());
phases
}
pub fn jar() -> Self {
let mut mapping = Self::new("jar");
mapping.bind(LifecyclePhase::ProcessResources, PluginBinding::resources("resources"));
mapping.bind(LifecyclePhase::Compile, PluginBinding::compiler("compile"));
mapping.bind(LifecyclePhase::ProcessTestResources, PluginBinding::resources("testResources"));
mapping.bind(LifecyclePhase::TestCompile, PluginBinding::compiler("testCompile"));
mapping.bind(LifecyclePhase::Test, PluginBinding::surefire("test"));
mapping.bind(LifecyclePhase::Package, PluginBinding::jar("jar"));
mapping.bind(LifecyclePhase::Install, PluginBinding::install("install"));
mapping.bind(LifecyclePhase::Deploy, PluginBinding::deploy("deploy"));
mapping
}
pub fn war() -> Self {
let mut mapping = Self::new("war");
mapping.bind(LifecyclePhase::ProcessResources, PluginBinding::resources("resources"));
mapping.bind(LifecyclePhase::Compile, PluginBinding::compiler("compile"));
mapping.bind(LifecyclePhase::ProcessTestResources, PluginBinding::resources("testResources"));
mapping.bind(LifecyclePhase::TestCompile, PluginBinding::compiler("testCompile"));
mapping.bind(LifecyclePhase::Test, PluginBinding::surefire("test"));
mapping.bind(LifecyclePhase::Package, PluginBinding::war("war"));
mapping.bind(LifecyclePhase::Install, PluginBinding::install("install"));
mapping.bind(LifecyclePhase::Deploy, PluginBinding::deploy("deploy"));
mapping
}
pub fn pom() -> Self {
let mut mapping = Self::new("pom");
mapping.bind(LifecyclePhase::Install, PluginBinding::install("install"));
mapping.bind(LifecyclePhase::Deploy, PluginBinding::deploy("deploy"));
mapping
}
pub fn ear() -> Self {
let mut mapping = Self::new("ear");
mapping.bind(LifecyclePhase::GenerateResources,
PluginBinding::new("org.apache.maven.plugins", "maven-ear-plugin", "3.3.0", "generate-application-xml"));
mapping.bind(LifecyclePhase::ProcessResources, PluginBinding::resources("resources"));
mapping.bind(LifecyclePhase::Package,
PluginBinding::new("org.apache.maven.plugins", "maven-ear-plugin", "3.3.0", "ear"));
mapping.bind(LifecyclePhase::Install, PluginBinding::install("install"));
mapping.bind(LifecyclePhase::Deploy, PluginBinding::deploy("deploy"));
mapping
}
pub fn ejb() -> Self {
let mut mapping = Self::new("ejb");
mapping.bind(LifecyclePhase::ProcessResources, PluginBinding::resources("resources"));
mapping.bind(LifecyclePhase::Compile, PluginBinding::compiler("compile"));
mapping.bind(LifecyclePhase::ProcessTestResources, PluginBinding::resources("testResources"));
mapping.bind(LifecyclePhase::TestCompile, PluginBinding::compiler("testCompile"));
mapping.bind(LifecyclePhase::Test, PluginBinding::surefire("test"));
mapping.bind(LifecyclePhase::Package,
PluginBinding::new("org.apache.maven.plugins", "maven-ejb-plugin", "3.2.1", "ejb"));
mapping.bind(LifecyclePhase::Install, PluginBinding::install("install"));
mapping.bind(LifecyclePhase::Deploy, PluginBinding::deploy("deploy"));
mapping
}
}
#[derive(Debug, Default)]
pub struct LifecycleMappingRegistry {
mappings: HashMap<String, LifecycleMapping>,
}
impl LifecycleMappingRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn with_defaults() -> Self {
let mut registry = Self::new();
registry.register(LifecycleMapping::jar());
registry.register(LifecycleMapping::war());
registry.register(LifecycleMapping::pom());
registry.register(LifecycleMapping::ear());
registry.register(LifecycleMapping::ejb());
registry
}
pub fn register(&mut self, mapping: LifecycleMapping) {
self.mappings.insert(mapping.packaging.clone(), mapping);
}
pub fn get(&self, packaging: &str) -> Option<&LifecycleMapping> {
self.mappings.get(packaging)
}
pub fn get_or_default(&self, packaging: &str) -> &LifecycleMapping {
self.mappings.get(packaging)
.or_else(|| self.mappings.get("jar"))
.expect("JAR mapping should always exist")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plugin_binding() {
let binding = PluginBinding::compiler("compile");
assert_eq!(binding.artifact_id, "maven-compiler-plugin");
assert_eq!(binding.goal, "compile");
}
#[test]
fn test_jar_lifecycle_mapping() {
let mapping = LifecycleMapping::jar();
let compile_bindings = mapping.get_bindings(&LifecyclePhase::Compile);
assert_eq!(compile_bindings.len(), 1);
assert_eq!(compile_bindings[0].goal, "compile");
let package_bindings = mapping.get_bindings(&LifecyclePhase::Package);
assert_eq!(package_bindings.len(), 1);
assert_eq!(package_bindings[0].goal, "jar");
}
#[test]
fn test_war_lifecycle_mapping() {
let mapping = LifecycleMapping::war();
let package_bindings = mapping.get_bindings(&LifecyclePhase::Package);
assert_eq!(package_bindings.len(), 1);
assert_eq!(package_bindings[0].goal, "war");
}
#[test]
fn test_pom_lifecycle_mapping() {
let mapping = LifecycleMapping::pom();
let compile_bindings = mapping.get_bindings(&LifecyclePhase::Compile);
assert!(compile_bindings.is_empty());
let install_bindings = mapping.get_bindings(&LifecyclePhase::Install);
assert_eq!(install_bindings.len(), 1);
}
#[test]
fn test_lifecycle_mapping_registry() {
let registry = LifecycleMappingRegistry::with_defaults();
assert!(registry.get("jar").is_some());
assert!(registry.get("war").is_some());
assert!(registry.get("pom").is_some());
let unknown = registry.get_or_default("unknown");
assert_eq!(unknown.packaging, "jar");
}
#[test]
fn test_phases_ordering() {
let mapping = LifecycleMapping::jar();
let phases = mapping.phases();
let compile_pos = phases.iter().position(|p| *p == LifecyclePhase::Compile);
let test_pos = phases.iter().position(|p| *p == LifecyclePhase::Test);
let package_pos = phases.iter().position(|p| *p == LifecyclePhase::Package);
assert!(compile_pos < test_pos);
assert!(test_pos < package_pos);
}
}