Etapa G frente Go: vendoring integrado en fetch — amfora construye, repro
Cierra el muro del frente Go (vendoring) replicando el patron de Rust: vendorear in-situ en el fetch (host, con red), no tarball-al-mirror. - fetch.rs: vendor_go_deps() analoga a vendor_cargo_deps — corre go mod vendor en el host si hay go.mod; el sandbox compila offline con -mod=vendor. - lib.rs: engancha vendor_go_deps tras los patches cuando el arbol trae go.mod (sin BuildSys::Go; el compile lo fija la receta en build.phases). - bootstrap-devfs.sh: instala el toolchain go del host (1.26.4, estatico) en .dev-fs/tools/go + symlink en ~/.cargo/bin (PATH del worker via .cargo/env). - amfora: PRIMERA receta Go del corpus. Build end-to-end validado (repo+commit -> fetch vendorea -> sandbox offline -> binario estatico que corre, Amfora v1.11.0). REPRODUCIBLE bit-a-bit: dos stores independientes dan of_tree b3:9ec1d5fe (trimpath + buildid= en el compile). Promovida al repo (282). Quedan 12 recetas Go en tandas/staged-2026-06-26/ (cheat/dnsx/croc/dyff/csvtk/ git-town/miller/jump/gron/qrcp/walk/gtrash): mecanico, copiar el patron de amfora ajustando el nombre del binario. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -234,6 +234,41 @@ pub fn vendor_cargo_deps(src: &Path) -> hammer_core::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Vendoriza los módulos de un proyecto Go en `<src>/vendor` para que `go build -mod=vendor`
|
||||
/// resuelva todo offline dentro del sandbox. La red se usa AQUÍ (fuera del sandbox, como
|
||||
/// `vendor_cargo_deps`): `go mod vendor` baja los módulos de `go.mod`/`go.sum` al árbol.
|
||||
///
|
||||
/// **Reproducible por `go.sum`:** a diferencia de Cargo (lock opcional), Go exige `go.sum`
|
||||
/// committeado con el hash de cada módulo; el mismo commit ⇒ el mismo `go.sum` ⇒ el mismo
|
||||
/// `vendor/` (ya hasheado dentro del commit que fija la receta). `GOTOOLCHAIN=local` impide que
|
||||
/// `go.mod` fuerce la auto-descarga de otra versión del toolchain (el del lab manda y queda fijo);
|
||||
/// `GOFLAGS=-mod=mod` permite poblar el `vendor/` aunque el árbol no lo traiga.
|
||||
///
|
||||
/// Un proyecto sin deps externas produce un `vendor/` vacío (o ninguno): inocuo.
|
||||
pub fn vendor_go_deps(src: &Path) -> hammer_core::Result<()> {
|
||||
let output = Command::new("go")
|
||||
.current_dir(src)
|
||||
.args(["mod", "vendor"])
|
||||
.env("GOFLAGS", "-mod=mod")
|
||||
.env("GOTOOLCHAIN", "local")
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
.map_err(|e| {
|
||||
hammer_core::Error::Other(anyhow::anyhow!(
|
||||
"spawn go mod vendor: {e} (¿está `go` en el PATH del host? lo provee el lab, \
|
||||
cf. scripts/bootstrap-devfs.sh / vps-setup.sh)"
|
||||
))
|
||||
})?;
|
||||
if !output.status.success() {
|
||||
return Err(hammer_core::Error::Other(anyhow::anyhow!(
|
||||
"go mod vendor falló (exit {:?})",
|
||||
output.status.code()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Aplica los patches de la receta (relativos a `recipe.base_dir`) sobre `tree`.
|
||||
pub fn apply_patches(recipe: &Recipe, tree: &Path) -> hammer_core::Result<()> {
|
||||
for p in &recipe.source.patches {
|
||||
|
||||
@@ -212,6 +212,16 @@ pub fn build(
|
||||
fetch::vendor_cargo_deps(&src_tree)?;
|
||||
}
|
||||
|
||||
// Recetas Go: análogo a Cargo. Si el árbol trae `go.mod`, vendoreamos los módulos (red en el
|
||||
// fetch) para que `go build -mod=vendor` resuelva offline en el sandbox. El toolchain `go` lo
|
||||
// aporta `deps.build = ["go"]` (recipes/go.toml) DENTRO del sandbox; el vendoring usa el `go`
|
||||
// del host (lo provee el lab). No hay BuildSys::Go: las recetas Go fijan el compile en
|
||||
// `[build.phases]` (ver tandas/staged-2026-06-26/amfora.toml como plantilla).
|
||||
if src_tree.join("go.mod").is_file() {
|
||||
tracing::info!("go: vendoreando módulos para build offline");
|
||||
fetch::vendor_go_deps(&src_tree)?;
|
||||
}
|
||||
|
||||
let out_dir = unique_out_dir(&cfg.work_root, &recipe.name, &h)?;
|
||||
let mut env: Vec<(String, String)> = Vec::new();
|
||||
if matches!(recipe.build.link, LinkMode::Static) {
|
||||
|
||||
Reference in New Issue
Block a user