1use std::path::Path;
6
7use crate::notes::links::{self, Link};
8use crate::notes::{Excerpt, git, has_note, note_of, write_note};
9
10pub fn wanted(repo: &Path, named: &[&str]) -> Result<Vec<String>, String> {
17 if !named.is_empty() {
18 return named.iter().map(|c| git(repo, &["rev-parse", "--verify", &format!("{c}^{{commit}}")]).ok_or(format!("{c} is not a commit"))).collect();
19 }
20 Ok(git(repo, &["rev-list", "--max-count=200", "HEAD"]).unwrap_or_default().lines().map(str::to_string).collect())
21}
22
23fn adopt(e: &mut Excerpt, records: &[Link]) -> bool {
25 links::adopt(&e.commit, &e.collective, records, &mut links::Lists { fixed_by: &mut e.fixed_by, fixes: &mut e.fixes })
26}
27
28fn relink(repo: &Path, commit: &str, records: &[Link]) -> Result<bool, String> {
30 let Some(mut e) = note_of(repo, commit) else { return Ok(false) };
31 if !adopt(&mut e, records) {
32 return Ok(false);
33 }
34 write_note(repo, &e).map(|()| true)
35}
36
37fn link_sides(commits: &[String], records: &[Link]) -> Vec<String> {
40 let mut out: Vec<String> = Vec::new();
41 for l in records.iter().filter(|l| commits.contains(&l.commit) || commits.contains(&l.fix)) {
42 for c in [&l.commit, &l.fix] {
43 if !out.contains(c) {
44 out.push(c.clone());
45 }
46 }
47 }
48 out
49}
50
51fn restore_excerpts(repo: &Path, text: &str, records: &[Link], commits: &[String]) -> Result<Vec<String>, String> {
54 let mut done: Vec<String> = Vec::new();
55 for mut e in text.lines().filter_map(|l| serde_json::from_str::<Excerpt>(l).ok()) {
56 if e.kind != "reasoning" || !commits.contains(&e.commit) || done.contains(&e.commit) {
57 continue;
58 }
59 if git(repo, &["cat-file", "-e", &format!("{}^{{commit}}", e.commit)]).is_none() || has_note(repo, &e.commit) {
60 continue;
61 }
62 adopt(&mut e, records);
63 write_note(repo, &e)?;
64 done.push(e.commit);
65 }
66 Ok(done)
67}
68
69pub fn restore(repo: &Path, store: &Path, commits: &[String]) -> Result<Vec<String>, String> {
77 let text = std::fs::read_to_string(store.join("reasoning.jsonl")).unwrap_or_default();
78 let records = links::records(&text);
79 let mut done = restore_excerpts(repo, &text, &records, commits)?;
80 let sides: Vec<String> = link_sides(commits, &records).into_iter().filter(|c| !done.contains(c)).collect();
81 for c in sides {
82 if relink(repo, &c, &records)? {
83 done.push(c);
84 }
85 }
86 Ok(done)
87}