use crate::doc::Doc;
use crate::error::{usage, Result};
use crate::links;
use crate::project::Project;
use crate::store::Store;
use crate::Ctx;
pub fn run_command(ctx: &Ctx) -> Result<()> {
let prj = ctx.open()?;
let n = run(&prj, ctx.backend.as_ref())?;
println!("synced {n} document(s)");
Ok(())
}
pub fn run(prj: &Project, backend: &dyn crate::backend::Backend) -> Result<usize> {
let (mut store, errs) = backend.load(prj)?;
if !errs.is_empty() {
return Err(usage("fix parse errors first (run verify)"));
}
let n = pass(prj, &mut store)?;
backend.flush(prj, store)?;
Ok(n)
}
pub fn pass(prj: &Project, store: &mut Store) -> Result<usize> {
let _ = std::fs::remove_file(prj.base.join("INDEX.md"));
let rows = store.full_rows()?;
let count = rows.len();
let mut docs: Vec<Doc> = Vec::with_capacity(count);
for r in &rows {
let mut doc = r.doc.clone();
let need_created = !doc.frontmatter.contains_key("created");
let need_updated = !doc.frontmatter.contains_key("updated");
if (need_created || need_updated) && r.orig_mtime.is_some() {
let ts = r.orig_mtime.clone().unwrap();
if need_created {
doc.frontmatter.set_str("created", ts.clone());
}
if need_updated {
doc.frontmatter.set_str("updated", ts);
}
}
docs.push(doc);
}
links::reconcile(&mut docs);
links::reconcile_blockers(&mut docs);
let index = links::build_index(&docs);
let prefixes: Vec<String> = prj.pcfg.types.values().map(|t| t.prefix.clone()).collect();
let re = links::ref_re(&prefixes);
for d in docs.iter_mut() {
let dir = d.path.parent().unwrap_or(&prj.base).to_path_buf();
d.body = links::linkify(&d.body, &dir, &index, &re);
}
for (r, d) in rows.iter().zip(&docs) {
if d.to_text() != r.doc.to_text() {
store.put_doc(&prj.pcfg, Some(r.dkey), d)?;
}
if let (Some(id), Some(status)) = (d.id(), d.status()) {
let canonical = prj
.pcfg
.doc_relpath(id, status)
.to_string_lossy()
.into_owned();
if canonical != r.relpath {
store.set_path(r.dkey, &canonical)?;
}
}
}
Ok(count)
}