rust-files: check for empty manifests caused by narrow
authorRaphaël Gomès <rgomes@octobus.net>
Wed, 02 Oct 2024 13:39:43 +0200
changeset 52072 78fc666a3e94
parent 52071 e1fe336c007a
child 52073 a8cf6a852f11
rust-files: check for empty manifests caused by narrow Explanations inline
rust/hg-core/src/operations/list_tracked_files.rs
rust/hg-core/src/revlog/manifest.rs
--- a/rust/hg-core/src/operations/list_tracked_files.rs	Wed Oct 02 13:36:51 2024 +0200
+++ b/rust/hg-core/src/operations/list_tracked_files.rs	Wed Oct 02 13:39:43 2024 +0200
@@ -8,7 +8,7 @@
 use std::num::NonZeroU8;
 
 use crate::errors::HgError;
-use crate::matchers::Matcher;
+use crate::matchers::{Matcher, VisitChildrenSet};
 use crate::repo::Repo;
 use crate::revlog::manifest::Manifest;
 use crate::revlog::RevlogError;
@@ -23,10 +23,7 @@
     narrow_matcher: Box<dyn Matcher + Sync>,
 ) -> Result<FilesForRev, RevlogError> {
     let rev = crate::revset::resolve_single(revset, repo)?;
-    Ok(FilesForRev {
-        manifest: repo.manifest_for_rev(rev.into())?,
-        narrow_matcher,
-    })
+    list_rev_tracked_files(repo, rev.into(), narrow_matcher)
 }
 
 /// List files under Mercurial control at a given revision.
@@ -35,8 +32,30 @@
     rev: UncheckedRevision,
     narrow_matcher: Box<dyn Matcher + Sync>,
 ) -> Result<FilesForRev, RevlogError> {
+    // TODO move this to the repo itself
+    // This implies storing the narrow matcher in the repo, bubbling up the
+    // errors and warnings, so it's a bit of churn. In the meantime, the repo
+    // method will error out on narrowed manifests.
+    let manifest = match repo.manifest_for_rev(rev) {
+        Ok(manifest) => manifest,
+        Err(e) => match e {
+            RevlogError::InvalidRevision(_) => {
+                let outside_of_current_narrow_spec = narrow_matcher
+                    .visit_children_set(HgPath::new(""))
+                    == VisitChildrenSet::Empty;
+                if outside_of_current_narrow_spec {
+                    // Fake a manifest for a manifest whose node is known, but
+                    // which doesn't exist because it's empty after narrowing
+                    Manifest::empty()
+                } else {
+                    return Err(e);
+                }
+            }
+            _ => return Err(e),
+        },
+    };
     Ok(FilesForRev {
-        manifest: repo.manifest_for_rev(rev)?,
+        manifest,
         narrow_matcher,
     })
 }
--- a/rust/hg-core/src/revlog/manifest.rs	Wed Oct 02 13:36:51 2024 +0200
+++ b/rust/hg-core/src/revlog/manifest.rs	Wed Oct 02 13:39:43 2024 +0200
@@ -87,6 +87,11 @@
 }
 
 impl Manifest {
+    /// Return a new empty manifest
+    pub fn empty() -> Self {
+        Self { bytes: vec![] }
+    }
+
     pub fn iter(
         &self,
     ) -> impl Iterator<Item = Result<ManifestEntry, HgError>> {