use std::path::Path;
use anyhow::{Result, Context};
use walkdir::WalkDir;
pub fn detect_main_class(base_dir: &Path) -> Result<Option<String>> {
let maven_src = base_dir.join("src/main/java");
if maven_src.exists() {
if let Some(main_class) = find_main_class_in_dir(&maven_src)? {
return Ok(Some(main_class));
}
}
let gradle_src = base_dir.join("src/main/java");
if gradle_src.exists() {
if let Some(main_class) = find_main_class_in_dir(&gradle_src)? {
return Ok(Some(main_class));
}
}
Ok(None)
}
fn find_main_class_in_dir(src_dir: &Path) -> Result<Option<String>> {
for entry in WalkDir::new(src_dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| {
e.path().extension()
.map(|ext| ext == "java")
.unwrap_or(false)
})
{
let path = entry.path();
if let Ok(content) = std::fs::read_to_string(path) {
if content.contains("public static void main") {
let package = extract_package_name(&content);
let relative = path.strip_prefix(src_dir)
.context("Failed to get relative path")?;
let class_name = relative
.to_string_lossy()
.replace(['/', '\\'], ".")
.trim_end_matches(".java")
.to_string();
let full_class_name = if let Some(pkg) = package {
format!("{pkg}.{class_name}")
} else {
class_name
};
return Ok(Some(full_class_name));
}
}
}
Ok(None)
}
fn extract_package_name(content: &str) -> Option<String> {
for line in content.lines() {
let trimmed = line.trim();
if trimmed.starts_with("package ") && trimmed.ends_with(';') {
let pkg = trimmed
.strip_prefix("package ")?
.strip_suffix(';')?
.trim();
return Some(pkg.to_string());
}
}
None
}
pub fn extract_main_class_from_config(base_dir: &Path) -> Result<Option<String>> {
let pom_path = base_dir.join("pom.xml");
if pom_path.exists() {
if let Ok(content) = std::fs::read_to_string(&pom_path) {
if let Some(start) = content.find("<mainClass>") {
if let Some(end) = content[start..].find("</mainClass>") {
let main_class = content[start + 11..start + end].trim();
if !main_class.is_empty() {
return Ok(Some(main_class.to_string()));
}
}
}
}
}
let gradle_path = base_dir.join("build.gradle");
if gradle_path.exists() {
if let Ok(content) = std::fs::read_to_string(&gradle_path) {
if let Some(start) = content.find("mainClass") {
let remaining = &content[start..];
if let Some(quote_start) = remaining.find('=') {
let after_eq = &remaining[quote_start + 1..].trim();
if let Some(quote_char) = after_eq.chars().next() {
if quote_char == '\'' || quote_char == '"' {
if let Some(quote_end) = after_eq[1..].find(quote_char) {
let main_class = after_eq[1..quote_end + 1].trim();
if !main_class.is_empty() {
return Ok(Some(main_class.to_string()));
}
}
}
}
}
}
}
}
Ok(None)
}