use std::path::PathBuf;
use anyhow::{Context, Result};
use caixa_core::{Caixa, LayoutInvariants, StandardLayout};
use clap::Args;
use super::load::{caixa_root, load_caixa};
#[derive(Args)]
pub struct Build {
#[arg(long)]
pub path: Option<PathBuf>,
}
impl Build {
pub fn run(self) -> Result<()> {
let root = caixa_root(self.path.as_deref());
let caixa = load_caixa(&root)?;
StandardLayout::new()
.verify(&caixa, &root)
.context("layout invariants violated")?;
for entry in caixa.bibliotecas() {
let path = root.join(entry);
let src = std::fs::read_to_string(&path)
.with_context(|| format!("reading {}", path.display()))?;
tatara_lisp::read(&src).with_context(|| format!("parsing {}", path.display()))?;
eprintln!(" ✓ {entry}");
}
eprintln!("{}", build_summary_line(&caixa));
Ok(())
}
}
pub(crate) fn build_summary_line(caixa: &Caixa) -> String {
format!(
"caixa {} v{} — layout + lisp parse clean ({} lib entry/ies)",
caixa.nome(),
caixa.versao(),
caixa.bibliotecas().len()
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn build_summary_line_routes_through_caixa_nome_and_versao_accessors() {
let caixa = Caixa::from_lisp(
r#"(defcaixa
:nome "b-summary"
:kind Biblioteca
:versao "0.2.3"
:bibliotecas ())"#,
)
.expect("parse");
let line = build_summary_line(&caixa);
assert_eq!(
line,
format!(
"caixa {} v{} — layout + lisp parse clean ({} lib entry/ies)",
caixa.nome(),
caixa.versao(),
caixa.bibliotecas().len()
),
"summary line must route the `{{nome}}` / `{{versao}}` / `{{n}}` \
scalars through the typed Caixa::nome / Caixa::versao / \
Caixa::bibliotecas accessors — any regression to the raw \
`caixa.nome` / `caixa.versao` field-accesses would silently \
pass today (accessors are `&self.<field>`) but drift on the \
first accessor extension"
);
assert!(
line.contains("caixa b-summary v0.2.3"),
"summary must carry the caixa's `:nome` / `:versao` verbatim \
(got: {line:?})"
);
assert!(
line.contains("(0 lib entry/ies)"),
"summary must carry the `:bibliotecas` entry count (got: {line:?})"
);
}
#[test]
fn build_summary_line_carries_nonzero_bibliotecas_count() {
let caixa = Caixa::from_lisp(
r#"(defcaixa
:nome "b-two-libs"
:kind Biblioteca
:versao "0.1.0"
:bibliotecas ("lib/a.lisp" "lib/b.lisp"))"#,
)
.expect("parse");
let line = build_summary_line(&caixa);
assert!(
line.contains("caixa b-two-libs v0.1.0"),
"summary must carry the caixa's `:nome` / `:versao` verbatim \
(got: {line:?})"
);
assert!(
line.contains("(2 lib entry/ies)"),
"summary must carry the actual `:bibliotecas` entry count \
(got: {line:?})"
);
}
}