diff --git a/crates/hammer-cli/src/nix_import.rs b/crates/hammer-cli/src/nix_import.rs index 26bad405..9d421236 100644 --- a/crates/hammer-cli/src/nix_import.rs +++ b/crates/hammer-cli/src/nix_import.rs @@ -28,6 +28,13 @@ pub struct NixPkg { pub build_inputs: Vec, #[serde(default)] pub native_build_inputs: Vec, + /// `true` si nixpkgs lo construye con `rustPlatform.buildRustPackage` (el wrapper lo detecta + /// por `cargoDeps`). Activa la plantilla Cargo de hammer (`--bin` + cp target/release). + #[serde(default)] + pub is_rust: bool, + /// El binario principal (`meta.mainProgram` de nix; p.ej. ripgrep→"rg"). Para el `--bin`. + #[serde(default)] + pub main_program: String, } /// El origen TAL CUAL lo da `nix eval` del `p.src`: la URL fetcheada + el `outputHash`/mode de la @@ -160,9 +167,26 @@ pub fn to_recipe_toml(pkg: &NixPkg) -> Result { format!("\n[deps]\nbuild = [{list}]\n") }; + // Rust (buildRustPackage): emite la plantilla Cargo de hammer — `--bin ` (cargo exige UN + // target) + install copiando `target/release/` a /out (mismo patrón que la receta ripgrep). + // El bin = meta.mainProgram de nix (ripgrep→rg), o el pname. Esto deja la receta build-ready. + let (flags_line, rust_install) = if pkg.is_rust { + let bin = if pkg.main_program.is_empty() { name.clone() } else { sanitize_name(&pkg.main_program) }; + ( + format!("flags = [\"--bin\", \"{bin}\"]\n"), + format!( + "\n[build.phases]\ninstall = \"mkdir -p /out/usr/bin && cp target/release/{bin} /out/usr/bin/{bin}\"\n" + ), + ) + } else { + ("flags = []\n".to_string(), String::new()) + }; + // configureFlags → una fase configure explícita (si las hay). Si no, se deja a la heurística // del lab. NOTA: muchos paquetes nix no son autotools (cmake/meson); esto es best-effort. - let phases_block = if pkg.configure_flags.is_empty() { + let phases_block = if !rust_install.is_empty() { + rust_install + } else if pkg.configure_flags.is_empty() { String::new() } else { let flags = pkg @@ -189,7 +213,7 @@ pub fn to_recipe_toml(pkg: &NixPkg) -> Result { compiler = \"zig-cc\"\n\ target = \"x86_64-linux-musl\"\n\ link = \"static\"\n\ - flags = []\n\ + {flags_line}\ {phases_block}{deps_block}" ); Ok(toml) @@ -372,6 +396,20 @@ mod tests { assert!(recipe.build.phases.configure.as_deref().unwrap().contains("--disable-nls")); } + #[test] + fn rust_package_gets_bin_and_install_template() { + let json = r#"{ + "pname": "ripgrep", "version": "14.1.1", + "source": { "url": "https://github.com/BurntSushi/ripgrep/archive/14.1.1.tar.gz", "output_hash_mode": "recursive" }, + "is_rust": true, "main_program": "rg" + }"#; + let pkg: NixPkg = serde_json::from_str(json).unwrap(); + let recipe = hammer_core::Recipe::from_toml(&to_recipe_toml(&pkg).unwrap()).unwrap(); + assert_eq!(recipe.build.flags, vec!["--bin", "rg"]); + let inst = recipe.build.phases.install.as_deref().unwrap(); + assert!(inst.contains("cp target/release/rg /out/usr/bin/rg"), "{inst}"); + } + #[test] fn filters_nix_stdenv_noise() { let json = r#"{ diff --git a/scripts/nix-import.sh b/scripts/nix-import.sh index 687ac94c..1a72c3b8 100755 --- a/scripts/nix-import.sh +++ b/scripts/nix-import.sh @@ -31,6 +31,9 @@ json=$(nix eval $NIXFLAGS --json "${NIXPKGS}#${ATTR}" --apply ' configure_flags = p.configureFlags or []; build_inputs = builtins.filter (s: s != "") (map (x: x.pname or x.name or "") (p.buildInputs or [])); native_build_inputs = builtins.filter (s: s != "") (map (x: x.pname or x.name or "") (p.nativeBuildInputs or [])); + # Rust: buildRustPackage setea cargoDeps ⇒ activa la plantilla Cargo del importador. + is_rust = builtins.hasAttr "cargoDeps" p; + main_program = p.meta.mainProgram or p.pname or ""; }') printf '%s' "$json" | $HAMMER import-nix -