- Hash encoded path are in .hg/store/dh instead of .hg/store/data.
- Path encoded index and data files may not have the same parent path. It is not just about replacing .i by .d
| Alphare |
| hg-reviewers |
| Automatic diff as part of commit; lint not applicable. |
| Automatic diff as part of commit; unit tests not applicable. |
| Path | Packages | |||
|---|---|---|---|---|
| M | rust/hg-core/src/operations/cat.rs (33 lines) | |||
| M | rust/hg-core/src/operations/debugdata.rs (2 lines) | |||
| M | rust/hg-core/src/revlog/changelog.rs (2 lines) | |||
| M | rust/hg-core/src/revlog/manifest.rs (2 lines) | |||
| M | rust/hg-core/src/revlog/revlog.rs (12 lines) |
| .parse::<Revision>() | .parse::<Revision>() | ||||
| .or(Err(DebugDataErrorKind::InvalidRevision))?; | .or(Err(DebugDataErrorKind::InvalidRevision))?; | ||||
| let root = find_root::FindRoot::new().run()?; | let root = find_root::FindRoot::new().run()?; | ||||
| let index_file = match self.kind { | let index_file = match self.kind { | ||||
| DebugDataKind::Changelog => root.join(".hg/store/00changelog.i"), | DebugDataKind::Changelog => root.join(".hg/store/00changelog.i"), | ||||
| DebugDataKind::Manifest => root.join(".hg/store/00manifest.i"), | DebugDataKind::Manifest => root.join(".hg/store/00manifest.i"), | ||||
| }; | }; | ||||
| let revlog = Revlog::open(&index_file)?; | let revlog = Revlog::open(&index_file, None)?; | ||||
| let data = revlog.get_rev_data(rev)?; | let data = revlog.get_rev_data(rev)?; | ||||
| Ok(data) | Ok(data) | ||||
| } | } | ||||
| } | } | ||||
| use crate::revlog::revlog::{Revlog, RevlogError}; | use crate::revlog::revlog::{Revlog, RevlogError}; | ||||
| use crate::revlog::Revision; | use crate::revlog::Revision; | ||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||
| /// A specialized `Revlog` to work with `changelog` data format. | /// A specialized `Revlog` to work with `changelog` data format. | ||||
| pub struct Changelog { | pub struct Changelog { | ||||
| /// The generic `revlog` format. | /// The generic `revlog` format. | ||||
| revlog: Revlog, | revlog: Revlog, | ||||
| } | } | ||||
| impl Changelog { | impl Changelog { | ||||
| /// Open the `changelog` of a repository given by its root. | /// Open the `changelog` of a repository given by its root. | ||||
| pub fn open(root: &PathBuf) -> Result<Self, RevlogError> { | pub fn open(root: &PathBuf) -> Result<Self, RevlogError> { | ||||
| let index_file = root.join(".hg/store/00changelog.i"); | let index_file = root.join(".hg/store/00changelog.i"); | ||||
| let revlog = Revlog::open(&index_file)?; | let revlog = Revlog::open(&index_file, None)?; | ||||
| Ok(Self { revlog }) | Ok(Self { revlog }) | ||||
| } | } | ||||
| /// Return the `ChangelogEntry` a given node id. | /// Return the `ChangelogEntry` a given node id. | ||||
| pub fn get_node( | pub fn get_node( | ||||
| &self, | &self, | ||||
| node: &[u8], | node: &[u8], | ||||
| ) -> Result<ChangelogEntry, RevlogError> { | ) -> Result<ChangelogEntry, RevlogError> { | ||||
| use crate::revlog::revlog::{Revlog, RevlogError}; | use crate::revlog::revlog::{Revlog, RevlogError}; | ||||
| use crate::revlog::Revision; | use crate::revlog::Revision; | ||||
| use crate::utils::hg_path::HgPath; | use crate::utils::hg_path::HgPath; | ||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||
| /// A specialized `Revlog` to work with `manifest` data format. | /// A specialized `Revlog` to work with `manifest` data format. | ||||
| pub struct Manifest { | pub struct Manifest { | ||||
| /// The generic `revlog` format. | /// The generic `revlog` format. | ||||
| revlog: Revlog, | revlog: Revlog, | ||||
| } | } | ||||
| impl Manifest { | impl Manifest { | ||||
| /// Open the `manifest` of a repository given by its root. | /// Open the `manifest` of a repository given by its root. | ||||
| pub fn open(root: &PathBuf) -> Result<Self, RevlogError> { | pub fn open(root: &PathBuf) -> Result<Self, RevlogError> { | ||||
| let index_file = root.join(".hg/store/00manifest.i"); | let index_file = root.join(".hg/store/00manifest.i"); | ||||
| let revlog = Revlog::open(&index_file)?; | let revlog = Revlog::open(&index_file, None)?; | ||||
| Ok(Self { revlog }) | Ok(Self { revlog }) | ||||
| } | } | ||||
| /// Return the `ManifestEntry` of a given node id. | /// Return the `ManifestEntry` of a given node id. | ||||
| pub fn get_node(&self, node: &[u8]) -> Result<ManifestEntry, RevlogError> { | pub fn get_node(&self, node: &[u8]) -> Result<ManifestEntry, RevlogError> { | ||||
| let rev = self.revlog.get_node_rev(node)?; | let rev = self.revlog.get_node_rev(node)?; | ||||
| self.get_rev(rev) | self.get_rev(rev) | ||||
| } | } | ||||
| } | } | ||||
| impl Revlog { | impl Revlog { | ||||
| /// Open a revlog index file. | /// Open a revlog index file. | ||||
| /// | /// | ||||
| /// It will also open the associated data file if index and data are not | /// It will also open the associated data file if index and data are not | ||||
| /// interleaved. | /// interleaved. | ||||
| #[timed] | #[timed] | ||||
| pub fn open(index_path: &Path) -> Result<Self, RevlogError> { | pub fn open( | ||||
| index_path: &Path, | |||||
| data_path: Option<&Path>, | |||||
| ) -> Result<Self, RevlogError> { | |||||
| let index_mmap = | let index_mmap = | ||||
| mmap_open(&index_path).map_err(RevlogError::IoError)?; | mmap_open(&index_path).map_err(RevlogError::IoError)?; | ||||
| let version = get_version(&index_mmap); | let version = get_version(&index_mmap); | ||||
| if version != 1 { | if version != 1 { | ||||
| return Err(RevlogError::UnsuportedVersion(version)); | return Err(RevlogError::UnsuportedVersion(version)); | ||||
| } | } | ||||
| let index = Index::new(Box::new(index_mmap))?; | let index = Index::new(Box::new(index_mmap))?; | ||||
| // TODO load data only when needed // | let default_data_path = index_path.with_extension("d"); | ||||
| // type annotation required | // type annotation required | ||||
| // won't recognize Mmap as Deref<Target = [u8]> | // won't recognize Mmap as Deref<Target = [u8]> | ||||
| let data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>> = | let data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>> = | ||||
| if index.is_inline() { | if index.is_inline() { | ||||
| None | None | ||||
| } else { | } else { | ||||
| let data_path = index_path.with_extension("d"); | let data_path = data_path.unwrap_or(&default_data_path); | ||||
| let data_mmap = | let data_mmap = | ||||
| mmap_open(&data_path).map_err(RevlogError::IoError)?; | mmap_open(data_path).map_err(RevlogError::IoError)?; | ||||
| Some(Box::new(data_mmap)) | Some(Box::new(data_mmap)) | ||||
| }; | }; | ||||
| Ok(Revlog { index, data_bytes }) | Ok(Revlog { index, data_bytes }) | ||||
| } | } | ||||
| /// Return number of entries of the `Revlog`. | /// Return number of entries of the `Revlog`. | ||||
| pub fn len(&self) -> usize { | pub fn len(&self) -> usize { | ||||
I don't like the use of format! instead of get_path_from_bytes, no need for UTF8 lossy conversion, that just gives the wrong impression. Maybe that wouldn't work on some platforms, even.