gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1389Shell 137Markdown 80Rust 802602 Definiciones

Etapa G capa-de-adaptación #3: traducir mirror:// de nix a URLs concretas

nix resuelve `mirror://<sitio>/...` 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 <noreply@anthropic.com>

b66cae91ae9fee19134827d0f3e04d3d37426166 · por sergio · (hace 4 meses) · padre 8e6c878d3 · ver el árbol en este commit

Delta semántico · 4

crates/hammer-cli/src/nix_import.rs

1 archivos · +46 −2

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<NixSource, String> {
                 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<NixSource, String> {
     }
 }
 
+/// Traduce el esquema `mirror://<sitio>/...` 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/<owner>/<repo>/archive/<rev>.tar.gz` o
 /// `https://codeload.github.com/<owner>/<repo>/tar.gz/<rev>`.
@@ -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#"{