# HG changeset patch # User Simon Sapin # Date 1611682306 -3600 # Node ID 4b381dbbf8b7a42e7f6e7e7d68e04886370d8aa7 # Parent 18a261b11b202abc79f765c360bd76d204ec9fef rhg: centralize parsing of `--rev` CLI arguments This new module will be the place to implement more of the revset language when we do so. Differential Revision: https://phab.mercurial-scm.org/D9873 diff -r 18a261b11b20 -r 4b381dbbf8b7 rust/hg-core/src/lib.rs --- a/rust/hg-core/src/lib.rs Mon Jan 25 18:25:26 2021 +0100 +++ b/rust/hg-core/src/lib.rs Tue Jan 26 18:31:46 2021 +0100 @@ -28,6 +28,7 @@ pub use revlog::*; pub mod config; pub mod operations; +pub mod revset; pub mod utils; use crate::utils::hg_path::{HgPathBuf, HgPathError}; diff -r 18a261b11b20 -r 4b381dbbf8b7 rust/hg-core/src/operations/cat.rs --- a/rust/hg-core/src/operations/cat.rs Mon Jan 25 18:25:26 2021 +0100 +++ b/rust/hg-core/src/operations/cat.rs Tue Jan 26 18:31:46 2021 +0100 @@ -15,8 +15,6 @@ use crate::revlog::revlog::Revlog; use crate::revlog::revlog::RevlogError; use crate::revlog::Node; -use crate::revlog::NodePrefix; -use crate::revlog::Revision; use crate::utils::files::get_path_from_bytes; use crate::utils::hg_path::{HgPath, HgPathBuf}; @@ -77,23 +75,15 @@ /// * `files`: The files to output. pub fn cat( repo: &Repo, - rev: &str, + revset: &str, files: &[HgPathBuf], ) -> Result, CatRevError> { + let rev = crate::revset::resolve_single(revset, repo)?; let changelog = Changelog::open(repo)?; let manifest = Manifest::open(repo)?; - - let changelog_entry = match rev.parse::() { - Ok(rev) => changelog.get_rev(rev)?, - _ => { - let changelog_node = NodePrefix::from_hex(&rev) - .map_err(|_| CatRevErrorKind::InvalidRevision)?; - changelog.get_node(changelog_node)? - } - }; + let changelog_entry = changelog.get_rev(rev)?; let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) .map_err(|_| CatRevErrorKind::CorruptedRevlog)?; - let manifest_entry = manifest.get_node(manifest_node.into())?; let mut bytes = vec![]; diff -r 18a261b11b20 -r 4b381dbbf8b7 rust/hg-core/src/operations/debugdata.rs --- a/rust/hg-core/src/operations/debugdata.rs Mon Jan 25 18:25:26 2021 +0100 +++ b/rust/hg-core/src/operations/debugdata.rs Tue Jan 26 18:31:46 2021 +0100 @@ -7,8 +7,6 @@ use crate::repo::Repo; use crate::revlog::revlog::{Revlog, RevlogError}; -use crate::revlog::NodePrefix; -use crate::revlog::Revision; /// Kind of data to debug #[derive(Debug, Copy, Clone)] @@ -79,7 +77,7 @@ /// Dump the contents data of a revision. pub fn debug_data( repo: &Repo, - rev: &str, + revset: &str, kind: DebugDataKind, ) -> Result, DebugDataError> { let index_file = match kind { @@ -87,16 +85,8 @@ DebugDataKind::Manifest => "00manifest.i", }; let revlog = Revlog::open(repo, index_file, None)?; - - let data = match rev.parse::() { - Ok(rev) => revlog.get_rev_data(rev)?, - _ => { - let node = NodePrefix::from_hex(&rev) - .map_err(|_| DebugDataErrorKind::InvalidRevision)?; - let rev = revlog.get_node_rev(node)?; - revlog.get_rev_data(rev)? - } - }; - + let rev = + crate::revset::resolve_rev_number_or_hex_prefix(revset, &revlog)?; + let data = revlog.get_rev_data(rev)?; Ok(data) } diff -r 18a261b11b20 -r 4b381dbbf8b7 rust/hg-core/src/operations/list_tracked_files.rs --- a/rust/hg-core/src/operations/list_tracked_files.rs Mon Jan 25 18:25:26 2021 +0100 +++ b/rust/hg-core/src/operations/list_tracked_files.rs Tue Jan 26 18:31:46 2021 +0100 @@ -9,9 +9,8 @@ use crate::repo::Repo; use crate::revlog::changelog::Changelog; use crate::revlog::manifest::{Manifest, ManifestEntry}; -use crate::revlog::node::{Node, NodePrefix}; +use crate::revlog::node::Node; use crate::revlog::revlog::RevlogError; -use crate::revlog::Revision; use crate::utils::hg_path::HgPath; use crate::{DirstateParseError, EntryState}; use rayon::prelude::*; @@ -137,19 +136,12 @@ /// List files under Mercurial control at a given revision. pub fn list_rev_tracked_files( repo: &Repo, - rev: &str, + revset: &str, ) -> Result { + let rev = crate::revset::resolve_single(revset, repo)?; let changelog = Changelog::open(repo)?; let manifest = Manifest::open(repo)?; - - let changelog_entry = match rev.parse::() { - Ok(rev) => changelog.get_rev(rev)?, - _ => { - let changelog_node = NodePrefix::from_hex(&rev) - .or(Err(ListRevTrackedFilesErrorKind::InvalidRevision))?; - changelog.get_node(changelog_node)? - } - }; + let changelog_entry = changelog.get_rev(rev)?; let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) .or(Err(ListRevTrackedFilesErrorKind::CorruptedRevlog))?; let manifest_entry = manifest.get_node(manifest_node.into())?; diff -r 18a261b11b20 -r 4b381dbbf8b7 rust/hg-core/src/revlog/changelog.rs --- a/rust/hg-core/src/revlog/changelog.rs Mon Jan 25 18:25:26 2021 +0100 +++ b/rust/hg-core/src/revlog/changelog.rs Tue Jan 26 18:31:46 2021 +0100 @@ -6,7 +6,7 @@ /// A specialized `Revlog` to work with `changelog` data format. pub struct Changelog { /// The generic `revlog` format. - revlog: Revlog, + pub(crate) revlog: Revlog, } impl Changelog { diff -r 18a261b11b20 -r 4b381dbbf8b7 rust/hg-core/src/revlog/revlog.rs --- a/rust/hg-core/src/revlog/revlog.rs Mon Jan 25 18:25:26 2021 +0100 +++ b/rust/hg-core/src/revlog/revlog.rs Tue Jan 26 18:31:46 2021 +0100 @@ -150,6 +150,11 @@ found_by_prefix.ok_or(RevlogError::InvalidRevision) } + /// Returns whether the given revision exists in this revlog. + pub fn has_rev(&self, rev: Revision) -> bool { + self.index.get_entry(rev).is_some() + } + /// Return the full data associated to a revision. /// /// All entries required to build the final data out of deltas will be diff -r 18a261b11b20 -r 4b381dbbf8b7 rust/hg-core/src/revset.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-core/src/revset.rs Tue Jan 26 18:31:46 2021 +0100 @@ -0,0 +1,53 @@ +//! The revset query language +//! +//! + +use crate::repo::Repo; +use crate::revlog::changelog::Changelog; +use crate::revlog::revlog::{Revlog, RevlogError}; +use crate::revlog::NodePrefix; +use crate::revlog::{Revision, NULL_REVISION}; + +/// Resolve a query string into a single revision. +/// +/// Only some of the revset language is implemented yet. +pub fn resolve_single( + input: &str, + repo: &Repo, +) -> Result { + let changelog = Changelog::open(repo)?; + + match resolve_rev_number_or_hex_prefix(input, &changelog.revlog) { + Err(RevlogError::InvalidRevision) => {} // Try other syntax + result => return result, + } + + if input == "null" { + return Ok(NULL_REVISION); + } + + // TODO: support for the rest of the language here. + + Err(RevlogError::InvalidRevision) +} + +/// Resolve the small subset of the language suitable for revlogs other than +/// the changelog, such as in `hg debugdata --manifest` CLI argument. +/// +/// * A non-negative decimal integer for a revision number, or +/// * An hexadecimal string, for the unique node ID that starts with this +/// prefix +pub fn resolve_rev_number_or_hex_prefix( + input: &str, + revlog: &Revlog, +) -> Result { + if let Ok(integer) = input.parse::() { + if integer >= 0 && revlog.has_rev(integer) { + return Ok(integer); + } + } + if let Ok(prefix) = NodePrefix::from_hex(input) { + return revlog.get_node_rev(prefix); + } + Err(RevlogError::InvalidRevision) +}