chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
Who vouched for a commit is found in process, not a git each merged pull
crates/knotless-serve/src/objects.rs+18−0
| @@ -575,6 +575,18 @@ impl Objects { | ||
} | ||
Ok(out) | ||
} | ||
| ||
/// The commits `to` reaches that `from` does not, as `git rev-list | ||
/// from..to` lists them, by id. An error when either is not here. | ||
pub fn between(&self, from: &str, to: &str) -> Result<HashSet<String>> { | ||
let tip = self.commit(to)?.id; | ||
let hidden = self.commit(from)?.id; | ||
let mut out = HashSet::new(); | ||
for info in self.0.rev_walk([tip]).with_hidden([hidden]).all()? { | ||
out.insert(info?.id.to_string()); | ||
} | ||
Ok(out) | ||
} | ||
} | ||
| ||
fn summary(commit: &gix::Commit<'_>) -> Result<Commit> { | ||
| @@ -728,6 +740,12 @@ mod tests { | ||
assert_eq!(o.brought("main", &[], 2).unwrap().len(), 2); | ||
assert!(o.brought("main", &["main"], 10).unwrap().is_empty()); | ||
assert!(o.brought("nope", &[], 10).is_err()); | ||
let past_side = o.brought("main", &["side"], 10).unwrap(); | ||
let past_side: HashSet<String> = past_side.into_iter().map(|c| c.sha).collect(); | ||
assert_eq!(o.between("side", "main").unwrap(), past_side); | ||
assert!(o.between("main", "main").unwrap().is_empty()); | ||
assert!(o.between("gone", "main").is_err()); | ||
assert!(o.between("side", "nope").is_err()); | ||
| ||
run(vec!["checkout", "-q", "--detach"]); | ||
assert_eq!(open(&d.join(".git")).unwrap().head(), None); | ||
crates/knotless-serve/src/web.rs+44−37
| @@ -1100,35 +1100,41 @@ fn coauthor(line: &str) -> Option<(String, String)> { | ||
Some((name.trim().to_string(), email.trim().to_string())) | ||
} | ||
| ||
/// What a merge as `merged` brought in, as `git rev-list` takes it: from | ||
/// where the base was before it, or, for a merge recorded without that, a | ||
/// merge commit's second parent less its first, which names nothing for | ||
/// any other kind of merge. | ||
fn brought(merged: &str, from: Option<&str>) -> String { | ||
/// What a merge as `merged` brought in, as the ends of a range of | ||
/// history: from where the base was before it, or, for a merge recorded | ||
/// without that, a merge commit's second parent less its first, which | ||
/// names nothing for any other kind of merge. | ||
fn brought(merged: &str, from: Option<&str>) -> (String, String) { | ||
match from { | ||
Some(from) => format!("{from}..{merged}"), | ||
None => format!("{merged}^1..{merged}^2"), | ||
Some(from) => (from.to_string(), merged.to_string()), | ||
None => (format!("{merged}^1"), format!("{merged}^2")), | ||
} | ||
} | ||
| ||
static BROUGHT: LazyLock<Mutex<HashMap<String, HashSet<String>>>> = LazyLock::new(Mutex::default); | ||
type Range = (String, String); | ||
| ||
/// The commits `range` names in `repo`, kept once git has found them: a | ||
/// merge never changes what it brought in. | ||
async fn brought_in(repo: &Repo, range: String) -> HashSet<String> { | ||
if let Some(known) = BROUGHT.lock().unwrap().get(&range) { | ||
return known.clone(); | ||
} | ||
let listed = repo.git.text(&["rev-list", &range], None).await; | ||
let shas: HashSet<String> = listed | ||
.iter() | ||
.flat_map(|l| l.lines()) | ||
.map(String::from) | ||
.collect(); | ||
if listed.is_ok() { | ||
BROUGHT.lock().unwrap().insert(range, shas.clone()); | ||
} | ||
shas | ||
static BROUGHT: LazyLock<Mutex<HashMap<Range, HashSet<String>>>> = LazyLock::new(Mutex::default); | ||
| ||
/// The commits each of `ranges` names in the mirror at `dir`, kept once | ||
/// found: a merge never changes what it brought in. Read in this process, | ||
/// all with the one repository opened, as a repository's merged pulls are | ||
/// many and a git process for each, all at once, took seconds. | ||
fn brought_in(dir: &std::path::Path, ranges: Vec<Option<Range>>) -> Vec<Option<HashSet<String>>> { | ||
let objects = crate::objects::open(dir).ok(); | ||
let find = |(from, to): Range| { | ||
if let Some(known) = BROUGHT.lock().unwrap().get(&(from.clone(), to.clone())) { | ||
return known.clone(); | ||
} | ||
// Not found, as a commit the mirror has yet to fetch, it is looked | ||
// for again next time. | ||
let found = objects.as_ref().map(|o| o.between(&from, &to)); | ||
let found = found.and_then(|f| f.ok()); | ||
if let Some(shas) = &found { | ||
BROUGHT.lock().unwrap().insert((from, to), shas.clone()); | ||
} | ||
found.unwrap_or_default() | ||
}; | ||
ranges.into_iter().map(|r| r.map(find)).collect() | ||
} | ||
| ||
/// Whose claims `repo`'s pages believe, and where: its owner, its | ||
| @@ -1141,7 +1147,7 @@ async fn vouched(app: &App, repo: &Repo, record: RepoRecord, items: &[Item]) -> | ||
}); | ||
let writers: Vec<String> = record.writers().map(String::from).collect(); | ||
let everywhere = std::iter::once(repo.did.clone()).chain(writers); | ||
let people: Vec<(String, Option<String>)> = everywhere | ||
let people: Vec<(String, Option<Range>)> = everywhere | ||
.map(|did| (did, None)) | ||
.chain(merged.map(|(did, range)| (did, Some(range)))) | ||
.collect(); | ||
| @@ -1154,17 +1160,17 @@ async fn vouched(app: &App, repo: &Repo, record: RepoRecord, items: &[Item]) -> | ||
}); | ||
let claimed: HashMap<String, Vec<String>> = | ||
futures::future::join_all(read).await.into_iter().collect(); | ||
futures::future::join_all(people.into_iter().map(|(did, range)| { | ||
let hashes = claimed.get(&did).cloned().unwrap_or_default(); | ||
async move { | ||
let only = match range { | ||
Some(range) => Some(brought_in(repo, range).await), | ||
None => None, | ||
}; | ||
let (dids, ranges): (Vec<String>, Vec<Option<Range>>) = people.into_iter().unzip(); | ||
let dir = repo.git.dir.clone(); | ||
let found = tokio::task::spawn_blocking(move || brought_in(&dir, ranges)); | ||
let found = found.await.expect("a walk does not panic"); | ||
dids.into_iter() | ||
.zip(found) | ||
.map(|(did, only)| { | ||
let hashes = claimed.get(&did).cloned().unwrap_or_default(); | ||
Vouched { did, hashes, only } | ||
} | ||
})) | ||
.await | ||
}) | ||
.collect() | ||
} | ||
| ||
/// `commits`, as the pages show them, each with the accounts that wrote it | ||
| @@ -3038,8 +3044,9 @@ mod tests { | ||
| ||
#[test] | ||
fn what_merges_brought() { | ||
assert_eq!(brought("m", Some("f")), "f..m"); | ||
assert_eq!(brought("m", None), "m^1..m^2"); | ||
let range = |from: &str, to: &str| (from.to_string(), to.to_string()); | ||
assert_eq!(brought("m", Some("f")), range("f", "m")); | ||
assert_eq!(brought("m", None), range("m^1", "m^2")); | ||
} | ||
| ||
#[test] | ||