Mercurial > hg-stable
changeset 45542:639f33f22faf
hg-core: add a `ListRevTrackedFiles` operation
List files tracked at a given revision.
Differential Revision: https://phab.mercurial-scm.org/D9014
author | Antoine Cezar <antoine.cezar@octobus.net> |
---|---|
date | Fri, 18 Sep 2020 16:52:16 +0200 |
parents | 72b7d58d6e35 |
children | 2f8227a12592 |
files | rust/hg-core/src/operations/list_tracked_files.rs rust/hg-core/src/operations/mod.rs rust/hg-core/src/revlog/index.rs rust/hg-core/src/revlog/revlog.rs |
diffstat | 4 files changed, 132 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-core/src/operations/list_tracked_files.rs Wed Sep 09 12:12:11 2020 +0200 +++ b/rust/hg-core/src/operations/list_tracked_files.rs Fri Sep 18 16:52:16 2020 +0200 @@ -6,14 +6,16 @@ // GNU General Public License version 2 or any later version. use crate::dirstate::parsers::parse_dirstate; +use crate::revlog::changelog::Changelog; +use crate::revlog::manifest::{Manifest, ManifestEntry}; +use crate::revlog::revlog::RevlogError; +use crate::revlog::Revision; use crate::utils::hg_path::HgPath; use crate::{DirstateParseError, EntryState}; use rayon::prelude::*; use std::convert::From; -use std::fmt; use std::fs; -use std::ops::Deref; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; /// Kind of error encountered by `ListDirstateTrackedFiles` #[derive(Debug)] @@ -31,14 +33,6 @@ pub kind: ListDirstateTrackedFilesErrorKind, } -impl std::error::Error for ListDirstateTrackedFilesError {} - -impl fmt::Display for ListDirstateTrackedFilesError { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - impl From<ListDirstateTrackedFilesErrorKind> for ListDirstateTrackedFilesError { @@ -84,3 +78,111 @@ Ok(files) } } + +/// Kind of error encountered by `ListRevTrackedFiles` +#[derive(Debug)] +pub enum ListRevTrackedFilesErrorKind { + /// Error when reading a `revlog` file. + IoError(std::io::Error), + /// The revision has not been found. + InvalidRevision, + /// A `revlog` file is corrupted. + CorruptedRevlog, + /// The `revlog` format version is not supported. + UnsuportedRevlogVersion(u16), + /// The `revlog` data format is not supported. + UnknowRevlogDataFormat(u8), +} + +/// A `ListRevTrackedFiles` error +#[derive(Debug)] +pub struct ListRevTrackedFilesError { + /// Kind of error encountered by `ListRevTrackedFiles` + pub kind: ListRevTrackedFilesErrorKind, +} + +impl From<ListRevTrackedFilesErrorKind> for ListRevTrackedFilesError { + fn from(kind: ListRevTrackedFilesErrorKind) -> Self { + ListRevTrackedFilesError { kind } + } +} + +impl From<RevlogError> for ListRevTrackedFilesError { + fn from(err: RevlogError) -> Self { + match err { + RevlogError::IoError(err) => { + ListRevTrackedFilesErrorKind::IoError(err) + } + RevlogError::UnsuportedVersion(version) => { + ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) + } + RevlogError::InvalidRevision => { + ListRevTrackedFilesErrorKind::InvalidRevision + } + RevlogError::Corrupted => { + ListRevTrackedFilesErrorKind::CorruptedRevlog + } + RevlogError::UnknowDataFormat(format) => { + ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) + } + } + .into() + } +} + +/// List files under Mercurial control at a given revision. +pub struct ListRevTrackedFiles<'a> { + /// The revision to list the files from. + rev: &'a str, + /// The changelog file + changelog: Changelog, + /// The manifest file + manifest: Manifest, + /// The manifest entry corresponding to the revision. + /// + /// Used to hold the owner of the returned references. + manifest_entry: Option<ManifestEntry>, +} + +impl<'a> ListRevTrackedFiles<'a> { + pub fn new( + root: &PathBuf, + rev: &'a str, + ) -> Result<Self, ListRevTrackedFilesError> { + let changelog = Changelog::open(&root)?; + let manifest = Manifest::open(&root)?; + + Ok(Self { + rev, + changelog, + manifest, + manifest_entry: None, + }) + } + + pub fn run( + &mut self, + ) -> Result<impl Iterator<Item = &HgPath>, ListRevTrackedFilesError> { + let changelog_entry = match self.rev.parse::<Revision>() { + Ok(rev) => self.changelog.get_rev(rev)?, + _ => { + let changelog_node = hex::decode(&self.rev).map_err(|_| { + ListRevTrackedFilesErrorKind::InvalidRevision + })?; + self.changelog.get_node(&changelog_node)? + } + }; + let manifest_node = hex::decode(&changelog_entry.manifest_node()?) + .map_err(|_| ListRevTrackedFilesErrorKind::CorruptedRevlog)?; + + self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?); + + if let Some(ref manifest_entry) = self.manifest_entry { + Ok(manifest_entry.files()) + } else { + panic!( + "manifest entry should have been stored in self.manifest_node to ensure its lifetime since references are returned from it" + ) + } + } +}
--- a/rust/hg-core/src/operations/mod.rs Wed Sep 09 12:12:11 2020 +0200 +++ b/rust/hg-core/src/operations/mod.rs Fri Sep 18 16:52:16 2020 +0200 @@ -14,6 +14,10 @@ ListDirstateTrackedFiles, ListDirstateTrackedFilesError, ListDirstateTrackedFilesErrorKind, }; +pub use list_tracked_files::{ + ListRevTrackedFiles, ListRevTrackedFilesError, + ListRevTrackedFilesErrorKind, +}; // TODO add an `Operation` trait when GAT have landed (rust #44265): // there is no way to currently define a trait which can both return
--- a/rust/hg-core/src/revlog/index.rs Wed Sep 09 12:12:11 2020 +0200 +++ b/rust/hg-core/src/revlog/index.rs Fri Sep 18 16:52:16 2020 +0200 @@ -44,6 +44,20 @@ } } + /// Return number of entries of the revlog index. + pub fn len(&self) -> usize { + if let Some(offsets) = &self.offsets { + offsets.len() + } else { + self.bytes.len() / INDEX_ENTRY_SIZE + } + } + + /// Returns `true` if the `Index` has zero `entries`. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + /// Return the index entry corresponding to the given revision if it /// exists. pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
--- a/rust/hg-core/src/revlog/revlog.rs Wed Sep 09 12:12:11 2020 +0200 +++ b/rust/hg-core/src/revlog/revlog.rs Fri Sep 18 16:52:16 2020 +0200 @@ -188,7 +188,7 @@ } /// Return the revlog index. - fn index(&self) -> Index { + pub fn index(&self) -> Index { let is_inline = self.data_bytes.is_none(); Index::new(&self.index_bytes, is_inline) }