app
[DEPRECATED] Chip Thumbnailer → adom-chip-thumbnailer
Public Made by Adomby adom
DEPRECATED: use adom/adom-chip-thumbnailer. No longer maintained.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
//! Pipeline runner: render all three thumbnails for one MPN, write a
//! `.thumb-errors.json` sidecar on partial failure, clear the
//! `.thumb-pending` marker only when ALL three succeed.
use crate::library::{self, ChipPaths};
use crate::ui::{ok, warn};
use crate::{manifest, render_3d, render_fp, render_sym};
use anyhow::Result;
#[derive(Debug, Default)]
pub struct RenderReport {
pub mpn: String,
pub sym_ok: bool,
pub fp_ok: bool,
pub three_d_ok: bool,
pub errors: Vec<(&'static str, String)>,
}
impl RenderReport {
pub fn all_ok(&self) -> bool {
self.sym_ok && self.fp_ok && self.three_d_ok
}
}
pub fn render_one(mpn: &str) -> Result<RenderReport> {
let chip = ChipPaths::for_mpn(mpn)?;
let mut report = RenderReport {
mpn: mpn.to_string(),
..Default::default()
};
if chip.kicad_sym.is_some() {
match render_sym::render(&chip) {
Ok(_) => {
report.sym_ok = true;
ok(format!("sym → {}", chip.symbol_thumb().display()));
}
Err(e) => {
report.errors.push(("sym", format!("{e}")));
warn(format!("sym failed: {e}"));
}
}
} else {
report.errors.push(("sym", "no .kicad_sym in chip dir".into()));
warn("sym skipped: no .kicad_sym");
}
if chip.kicad_mod.is_some() {
match render_fp::render(&chip) {
Ok(_) => {
report.fp_ok = true;
ok(format!("fp → {}", chip.footprint_thumb().display()));
}
Err(e) => {
report.errors.push(("fp", format!("{e}")));
warn(format!("fp failed: {e}"));
}
}
} else {
report.errors.push(("fp", "no .kicad_mod in chip dir".into()));
warn("fp skipped: no .kicad_mod");
}
if chip.step.is_some() {
match render_3d::render(&chip) {
Ok(_) => {
report.three_d_ok = true;
ok(format!("3d → {}", chip.three_d_thumb().display()));
}
Err(e) => {
report.errors.push(("3d", format!("{e}")));
warn(format!("3d failed: {e}"));
}
}
} else {
report.errors.push(("3d", "no .step in chip dir".into()));
warn("3d skipped: no .step");
}
if report.all_ok() {
library::clear_pending(mpn)?;
library::clear_errors(mpn);
} else if !report.errors.is_empty() {
let kinds: Vec<(&str, String)> = report
.errors
.iter()
.map(|(k, v)| (*k, v.clone()))
.collect();
let _ = library::write_errors(mpn, &kinds);
}
// Always (re)write the manifest — even on partial render, so downstream
// apps can see what's available and what's missing.
match manifest::write(&chip) {
Ok(path) => ok(format!("manifest → {}", path.display())),
Err(e) => warn(format!("manifest write failed: {e}")),
}
Ok(report)
}
pub fn render_pending() -> Result<usize> {
let mut n = 0;
for mpn in library::pending_chips()? {
let _ = render_one(&mpn);
n += 1;
}
Ok(n)
}