//! La `Recipe`: descripción pura de un build. Ver `docs/02-build-lab.md` §1. use serde::{Deserialize, Serialize}; use crate::hash::ArtifactHash; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Recipe { pub name: String, pub version: String, pub source: Source, pub build: Build, #[serde(default)] pub deps: Deps, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Source { pub repo: String, /// Commit FIJADO. Nunca "HEAD". Ver ADR 0006. pub commit: String, #[serde(default)] pub patches: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Build { #[serde(default)] pub compiler: Compiler, #[serde(default = "default_target")] pub target: String, #[serde(default)] pub link: LinkMode, #[serde(default)] pub flags: Vec, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Deps { #[serde(default)] pub build: Vec, #[serde(default)] pub runtime: Vec, } /// Compilador del lab, POR RECETA (no global). `zig-cc` por defecto; escotilla a clang/gcc /// para paquetes con gcc-ismos. Ver ADR 0003. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum Compiler { #[default] ZigCc, Clang, Gcc, } impl Compiler { pub fn as_str(&self) -> &'static str { match self { Compiler::ZigCc => "zig-cc", Compiler::Clang => "clang", Compiler::Gcc => "gcc", } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum LinkMode { #[default] Static, Dynamic, } fn default_target() -> String { "x86_64-linux-musl".to_string() } impl Recipe { pub fn from_toml(_s: &str) -> crate::Result { // TODO(fase-0): parsear TOML. Por ahora el parsing real lo añadiremos al implementar // `hammer build`; el contrato (esta struct) ya está fijado. Err(crate::Error::Recipe( "parsing de receta TOML pendiente (Fase 0)".into(), )) } /// Las entradas canónicas que alimentan el `ArtifactHash` de esta receta. /// NOTA: el hash final también incorpora los hashes de las deps de build (recursivo), /// que el lab resuelve antes de llamar aquí. Ver `docs/02-build-lab.md` §2 y §5. pub fn hash_inputs(&self, dep_hashes: &[ArtifactHash]) -> Vec> { let mut v: Vec> = vec![ self.source.commit.as_bytes().to_vec(), self.build.compiler.as_str().as_bytes().to_vec(), self.build.target.as_bytes().to_vec(), format!("{:?}", self.build.link).into_bytes(), ]; for p in &self.source.patches { v.push(p.as_bytes().to_vec()); } for f in &self.build.flags { v.push(f.as_bytes().to_vec()); } for d in dep_hashes { v.push(d.as_str().as_bytes().to_vec()); } v } }