Etapa G: detect_go_main ve el main bajo header de comentario de bloque

cmd/helm/helm.go arranca con un header Apache /* ... */ cuyas líneas internas no llevan '*';
el filtro por-línea ingenuo de is_main_go cortaba en 'Copyright ...' y daba 'no es main' ⇒
detect_go_main no hallaba cmd/helm y caía a '.' (raíz sin .go → 'no Go files in /src'). Ahora
rastrea el estado dentro/fuera de bloque /* */. Afecta a cualquier .go con header de bloque.
Test: detect_go_main_sees_main_under_block_comment_header.
This commit is contained in:
2026-06-26 23:38:47 -04:00
parent 06ba417336
commit 3b23463ac1
+50 -2
View File
@@ -488,11 +488,45 @@ fn detect_build_system(src: &Path) -> BuildSys {
fn detect_go_main(src: &Path) -> String {
fn is_main_go(path: &Path) -> bool {
let Ok(text) = std::fs::read_to_string(path) else { return false };
// El primer token significativo de un .go es la cláusula `package` (tras build-constraints
// `//go:build`, comentarios de línea y el header de licencia). Hay que saltar comentarios de
// BLOQUE `/* ... */` correctamente: muchos headers Apache son `/*\nCopyright ...\n*/` y las
// líneas internas NO arrancan con `*` ⇒ un filtro por-línea ingenuo cortaría ahí y fallaría
// (p.ej. cmd/helm/helm.go). Escaneamos rastreando el estado dentro/fuera de bloque.
let mut in_block = false;
for line in text.lines() {
let l = line.trim();
if l.is_empty() || l.starts_with("//") || l.starts_with("/*") || l.starts_with('*') {
let mut l = line.trim();
if in_block {
match l.find("*/") {
Some(i) => {
l = l[i + 2..].trim();
in_block = false;
}
None => continue,
}
}
if l.is_empty() || l.starts_with("//") {
continue;
}
if let Some(i) = l.find("/*") {
let before = l[..i].trim();
if !before.is_empty() {
return before.starts_with("package main");
}
match l[i + 2..].find("*/") {
Some(j) => {
let after = l[i + 2 + j + 2..].trim();
if after.is_empty() {
continue;
}
return after.starts_with("package main");
}
None => {
in_block = true;
continue;
}
}
}
return l.starts_with("package main");
}
false
@@ -800,6 +834,20 @@ commit = "deadbeef"
assert_eq!(detect_go_main(d.path()), "./cmd/mlr");
}
#[test]
fn detect_go_main_sees_main_under_block_comment_header() {
// header de licencia `/* ... */` con líneas internas SIN `*` (estilo Apache de helm):
// el main en cmd/helm debe detectarse igual (regresión del corte ingenuo por-línea).
let d = tempfile::tempdir().unwrap();
std::fs::create_dir_all(d.path().join("cmd/helm")).unwrap();
std::fs::write(
d.path().join("cmd/helm/helm.go"),
b"/*\nCopyright The Helm Authors.\nLicensed under the Apache License 2.0\n*/\n\npackage main\n\nfunc main() {}\n",
)
.unwrap();
assert_eq!(detect_go_main(d.path()), "./cmd/helm");
}
#[test]
fn detect_autoconf_raw_when_only_configure_ac() {
let d = tempfile::tempdir().unwrap();