use std::path::PathBuf;
use std::process::Command;
use anyhow::{Context, Result};
pub struct ExternalMavenExecutor;
impl ExternalMavenExecutor {
pub fn execute_plugin_goal(
&self,
group_id: &str,
artifact_id: &str,
version: &str,
goal: &str,
project_dir: &PathBuf,
) -> Result<()> {
let mvn_exe = Self::find_maven()
.ok_or_else(|| anyhow::anyhow!("Maven not found. Please ensure mvn is in PATH"))?;
tracing::info!(
"Executing plugin {}:{}:{}:{} via external Maven process",
group_id, artifact_id, version, goal
);
let goal_string = format!("{group_id}:{artifact_id}:{version}:{goal}");
let output = Command::new(&mvn_exe)
.arg(&goal_string)
.current_dir(project_dir)
.output()
.with_context(|| format!("Failed to execute Maven command: {goal_string}"))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(anyhow::anyhow!(
"Maven plugin execution failed: {stderr}"
));
}
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.is_empty() {
tracing::debug!("Maven output:\n{}", stdout);
}
Ok(())
}
fn find_maven() -> Option<PathBuf> {
if let Ok(m2_home) = std::env::var("M2_HOME") {
let mvn_path = PathBuf::from(m2_home)
.join("bin")
.join(if cfg!(windows) { "mvn.cmd" } else { "mvn" });
if mvn_path.exists() {
return Some(mvn_path);
}
}
if let Ok(maven_home) = std::env::var("MAVEN_HOME") {
let mvn_path = PathBuf::from(maven_home)
.join("bin")
.join(if cfg!(windows) { "mvn.cmd" } else { "mvn" });
if mvn_path.exists() {
return Some(mvn_path);
}
}
which::which("mvn").ok()
}
pub fn is_available() -> bool {
Self::find_maven().is_some()
}
}