--- a/rust/hg-core/src/revlog/index.rs Thu Aug 03 15:01:34 2023 +0200
+++ b/rust/hg-core/src/revlog/index.rs Thu Aug 03 15:50:14 2023 +0200
@@ -512,6 +512,50 @@
}
}
+ /// Obtain the delta chain for a revision.
+ ///
+ /// `stop_rev` specifies a revision to stop at. If not specified, we
+ /// stop at the base of the chain.
+ ///
+ /// Returns a 2-tuple of (chain, stopped) where `chain` is a vec of
+ /// revs in ascending order and `stopped` is a bool indicating whether
+ /// `stoprev` was hit.
+ pub fn delta_chain(
+ &self,
+ rev: Revision,
+ stop_rev: Option<Revision>,
+ ) -> Result<(Vec<Revision>, bool), HgError> {
+ let mut current_rev = rev;
+ let mut entry = self.get_entry(rev).unwrap();
+ let mut chain = vec![];
+ while current_rev.0 != entry.base_revision_or_base_of_delta_chain().0
+ && stop_rev.map(|r| r != current_rev).unwrap_or(true)
+ {
+ chain.push(current_rev);
+ let new_rev = if self.uses_generaldelta() {
+ entry.base_revision_or_base_of_delta_chain()
+ } else {
+ UncheckedRevision(current_rev.0 - 1)
+ };
+ if new_rev.0 == NULL_REVISION.0 {
+ break;
+ }
+ current_rev = self.check_revision(new_rev).ok_or_else(|| {
+ HgError::corrupted(format!("Revision {new_rev} out of range"))
+ })?;
+ entry = self.get_entry(current_rev).unwrap()
+ }
+
+ let stopped = if stop_rev.map(|r| current_rev == r).unwrap_or(false) {
+ true
+ } else {
+ chain.push(current_rev);
+ false
+ };
+ chain.reverse();
+ Ok((chain, stopped))
+ }
+
pub fn find_snapshots(
&self,
start_rev: UncheckedRevision,
--- a/rust/hg-cpython/src/revlog.rs Thu Aug 03 15:01:34 2023 +0200
+++ b/rust/hg-cpython/src/revlog.rs Thu Aug 03 15:50:14 2023 +0200
@@ -310,7 +310,40 @@
/// determine revisions with deltas to reconstruct fulltext
def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
- self.call_cindex(py, "deltachain", args, kw)
+ let index = self.index(py).borrow();
+ let rev = args.get_item(py, 0).extract::<BaseRevision>(py)?.into();
+ let stop_rev =
+ args.get_item(py, 1).extract::<Option<BaseRevision>>(py)?;
+ let rev = index.check_revision(rev).ok_or_else(|| {
+ nodemap_error(py, NodeMapError::RevisionNotInIndex(rev))
+ })?;
+ let stop_rev = if let Some(stop_rev) = stop_rev {
+ let stop_rev = UncheckedRevision(stop_rev);
+ Some(index.check_revision(stop_rev).ok_or_else(|| {
+ nodemap_error(py, NodeMapError::RevisionNotInIndex(stop_rev))
+ })?)
+ } else {None};
+ let (chain, stopped) = index.delta_chain(rev, stop_rev).map_err(|e| {
+ PyErr::new::<cpython::exc::ValueError, _>(py, e.to_string())
+ })?;
+
+ let cresult = self.call_cindex(py, "deltachain", args, kw)?;
+ let cchain: Vec<BaseRevision> =
+ cresult.get_item(py, 0)?.extract::<Vec<BaseRevision>>(py)?;
+ let chain: Vec<_> = chain.into_iter().map(|r| r.0).collect();
+ assert_eq!(chain, cchain);
+ assert_eq!(stopped, cresult.get_item(py, 1)?.extract(py)?);
+
+ Ok(
+ PyTuple::new(
+ py,
+ &[
+ chain.into_py_object(py).into_object(),
+ stopped.into_py_object(py).into_object()
+ ]
+ ).into_object()
+ )
+
}
/// slice planned chunk read to reach a density threshold