rhg: do not fail when the repo is empty
Differential Revision: https://phab.mercurial-scm.org/D11651
--- a/rust/hg-core/src/revlog/revlog.rs Tue Oct 12 19:43:51 2021 +0100
+++ b/rust/hg-core/src/revlog/revlog.rs Wed Oct 13 10:17:27 2021 -0700
@@ -70,15 +70,21 @@
data_path: Option<&Path>,
) -> Result<Self, HgError> {
let index_path = index_path.as_ref();
- let index_mmap = repo.store_vfs().mmap_open(&index_path)?;
+ let index = {
+ match repo.store_vfs().mmap_open_opt(&index_path)? {
+ None => Index::new(Box::new(vec![])),
+ Some(index_mmap) => {
+ let version = get_version(&index_mmap)?;
+ if version != 1 {
+ // A proper new version should have had a repo/store requirement.
+ return Err(HgError::corrupted("corrupted revlog"));
+ }
- let version = get_version(&index_mmap)?;
- if version != 1 {
- // A proper new version should have had a repo/store requirement.
- return Err(HgError::corrupted("corrupted revlog"));
- }
-
- let index = Index::new(Box::new(index_mmap))?;
+ let index = Index::new(Box::new(index_mmap))?;
+ Ok(index)
+ }
+ }
+ }?;
let default_data_path = index_path.with_extension("d");
@@ -418,6 +424,6 @@
.with_version(1)
.build();
- assert_eq!(get_version(&bytes), 1)
+ assert_eq!(get_version(&bytes).map_err(|_err|()), Ok(1))
}
}
--- a/rust/hg-core/src/vfs.rs Tue Oct 12 19:43:51 2021 +0100
+++ b/rust/hg-core/src/vfs.rs Wed Oct 13 10:17:27 2021 -0700
@@ -9,6 +9,8 @@
pub(crate) base: &'a Path,
}
+struct FileNotFound(std::io::Error, PathBuf);
+
impl Vfs<'_> {
pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
self.base.join(relative_path)
@@ -22,16 +24,41 @@
std::fs::read(&path).when_reading_file(&path)
}
+ fn mmap_open_gen(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<Result<Mmap, FileNotFound>, HgError> {
+ let path = self.join(relative_path);
+ let file = match std::fs::File::open(&path) {
+ Err(err) => {
+ if let ErrorKind::NotFound = err.kind() {
+ return Ok(Err(FileNotFound(err, path)));
+ };
+ return (Err(err)).when_reading_file(&path);
+ }
+ Ok(file) => file,
+ };
+ // TODO: what are the safety requirements here?
+ let mmap = unsafe { MmapOptions::new().map(&file) }
+ .when_reading_file(&path)?;
+ Ok(Ok(mmap))
+ }
+
+ pub fn mmap_open_opt(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<Option<Mmap>, HgError> {
+ self.mmap_open_gen(relative_path).map(|res| res.ok())
+ }
+
pub fn mmap_open(
&self,
relative_path: impl AsRef<Path>,
) -> Result<Mmap, HgError> {
- let path = self.base.join(relative_path);
- let file = std::fs::File::open(&path).when_reading_file(&path)?;
- // TODO: what are the safety requirements here?
- let mmap = unsafe { MmapOptions::new().map(&file) }
- .when_reading_file(&path)?;
- Ok(mmap)
+ match self.mmap_open_gen(relative_path)? {
+ Err(FileNotFound(err, path)) => Err(err).when_reading_file(&path),
+ Ok(res) => Ok(res),
+ }
}
pub fn rename(
--- a/tests/test-empty-manifest-index.t Tue Oct 12 19:43:51 2021 +0100
+++ b/tests/test-empty-manifest-index.t Wed Oct 13 10:17:27 2021 -0700
@@ -1,23 +1,27 @@
-Create a repo such that the changelog entry refers to a null manifest node:
+Test null revisions (node 0000000000000000000000000000000000000000, aka rev -1)
+in various circumstances.
+
+Make an empty repo:
$ hg init a
$ cd a
- $ hg log
- $ touch x
- $ hg add x
- $ hg commit -m "init"
- $ hg rm x
- $ hg commit -q --amend
- $ wc -c < .hg/store/00manifest.i
- 0
-
-Make sure that the manifest can be read (and is empty):
-
- $ hg --config rhg.on-unsupported=abort files -r .
+ $ hg files -r 0000000000000000000000000000000000000000
+ [1]
+ $ hg files -r .
[1]
-Test a null changelog rev, too:
+Add an empty commit (this makes the changelog refer to a null manifest node):
+
+
+ $ hg commit -m "init" --config ui.allowemptycommit=true
- $ hg --config rhg.on-unsupported=abort files -r 0000000000000000000000000000000000000000
+ $ hg files -r .
[1]
+
+Strip that empty commit (this makes the changelog file empty, as opposed to missing):
+
+ $ hg --config 'extensions.strip=' strip . > /dev/null
+
+ $ hg files -r .
+ [1]