From b66cae91ae9fee19134827d0f3e04d3d37426166 Mon Sep 17 00:00:00 2001 From: sergio Date: Sun, 21 Jun 2026 08:20:08 -0400 Subject: [PATCH] =?UTF-8?q?Etapa=20G=20capa-de-adaptaci=C3=B3n=20#3:=20tra?= =?UTF-8?q?ducir=20mirror://=20de=20nix=20a=20URLs=20concretas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nix resuelve `mirror:///...` en eval; un import los deja literales y el curl de hammer no los entiende. expand_nix_mirror() mapea los comunes (gnu/savannah/kernel/sourceforge/gnome/ apache/xorg/pypi/cpan/debian) a un espejo real; lo no mapeado se deja igual. +1 test. Validado: import hello → tarball https://ftp.gnu.org/gnu/hello/... (antes mirror://gnu/...). Co-Authored-By: Claude Opus 4.8 --- crates/hammer-cli/src/nix_import.rs | 48 +++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/crates/hammer-cli/src/nix_import.rs b/crates/hammer-cli/src/nix_import.rs index 12402b37..26bad405 100644 --- a/crates/hammer-cli/src/nix_import.rs +++ b/crates/hammer-cli/src/nix_import.rs @@ -63,7 +63,7 @@ pub fn classify_source(raw: &RawSource) -> Result { return Err(format!("source flat sin hash: {}", raw.url)); } let hex = nix_hash_to_hex(&raw.output_hash)?; - Ok(NixSource::Tarball { url: raw.url.clone(), sha256: hex }) + Ok(NixSource::Tarball { url: expand_nix_mirror(&raw.url), sha256: hex }) } "recursive" => Err(format!( "source recursivo no-github (hash NAR no reusable): {} — fijá repo+commit a mano", @@ -73,6 +73,33 @@ pub fn classify_source(raw: &RawSource) -> Result { } } +/// Traduce el esquema `mirror:///...` de nix a una URL concreta. nix resuelve estos +/// mirrors en tiempo de eval; un import los deja literales y el fetch de hammer (curl) no los +/// entiende. Mapeamos los más comunes a un mirror real; lo no mapeado se deja igual + el usuario +/// elige espejo. (nixpkgs tiene la lista completa en `pkgs/build-support/fetchurl/mirrors.nix`.) +fn expand_nix_mirror(url: &str) -> String { + let Some(rest) = url.strip_prefix("mirror://") else { + return url.to_string(); + }; + let Some((site, path)) = rest.split_once('/') else { + return url.to_string(); + }; + let base = match site { + "gnu" => "https://ftp.gnu.org/gnu/", + "savannah" => "https://download.savannah.gnu.org/releases/", + "kernel" => "https://www.kernel.org/pub/", + "sourceforge" => "https://downloads.sourceforge.net/", + "gnome" => "https://download.gnome.org/", + "apache" => "https://dlcdn.apache.org/", + "xorg" => "https://www.x.org/releases/", + "pypi" => "https://files.pythonhosted.org/packages/", + "cpan" => "https://cpan.metacpan.org/", + "debian" => "https://deb.debian.org/debian/", + _ => return url.to_string(), // desconocido: dejamos el mirror:// (el humano resuelve) + }; + format!("{base}{path}") +} + /// Extrae `(owner, repo, rev)` de una URL de descarga de GitHub (las que arma `fetchFromGitHub`): /// `https://github.com///archive/.tar.gz` o /// `https://codeload.github.com///tar.gz/`. @@ -335,7 +362,8 @@ mod tests { let recipe = hammer_core::Recipe::from_toml(&toml).expect("recipe válida"); assert_eq!(recipe.name, "hello"); assert_eq!(recipe.version, "2.12.1"); - assert_eq!(recipe.source.tarball.as_deref(), Some("mirror://gnu/hello/hello-2.12.1.tar.gz")); + // mirror://gnu/ se traduce a una URL concreta que el fetch de hammer entiende. + assert_eq!(recipe.source.tarball.as_deref(), Some("https://ftp.gnu.org/gnu/hello/hello-2.12.1.tar.gz")); assert_eq!( recipe.source.sha256.as_deref(), Some("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") @@ -360,6 +388,22 @@ mod tests { assert_eq!(recipe.deps.build, vec!["pcre2", "rustc"]); } + #[test] + fn expands_common_nix_mirrors() { + assert_eq!( + expand_nix_mirror("mirror://gnu/hello/hello-2.12.1.tar.gz"), + "https://ftp.gnu.org/gnu/hello/hello-2.12.1.tar.gz" + ); + assert_eq!( + expand_nix_mirror("mirror://savannah/foo/foo-1.tar.gz"), + "https://download.savannah.gnu.org/releases/foo/foo-1.tar.gz" + ); + // desconocido se deja igual (no rompe, el humano resuelve). + assert_eq!(expand_nix_mirror("mirror://raro/x"), "mirror://raro/x"); + // url normal pasa sin tocar. + assert_eq!(expand_nix_mirror("https://x/y.tar.gz"), "https://x/y.tar.gz"); + } + #[test] fn import_github_uses_git() { let json = r#"{