Patchwork D9873: rhg: centralize parsing of `--rev` CLI arguments

login
register
mail settings
Submitter phabricator
Date Jan. 26, 2021, 5:45 p.m.
Message ID <differential-rev-PHID-DREV-fbwnctkuwvll7m74qrcz-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/48184/
State Superseded
Headers show

Comments

phabricator - Jan. 26, 2021, 5:45 p.m.
SimonSapin created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  This new module will be the place to implement more of the revset language
  when we do so.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D9873

AFFECTED FILES
  rust/hg-core/src/lib.rs
  rust/hg-core/src/operations/cat.rs
  rust/hg-core/src/operations/debugdata.rs
  rust/hg-core/src/operations/list_tracked_files.rs
  rust/hg-core/src/revlog/changelog.rs
  rust/hg-core/src/revlog/revlog.rs
  rust/hg-core/src/revset.rs

CHANGE DETAILS




To: SimonSapin, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/rust/hg-core/src/revset.rs b/rust/hg-core/src/revset.rs
new file mode 100644
--- /dev/null
+++ b/rust/hg-core/src/revset.rs
@@ -0,0 +1,53 @@ 
+//! The revset query language
+//!
+//! <https://www.mercurial-scm.org/repo/hg/help/revsets>
+
+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<Revision, RevlogError> {
+    let changelog = Changelog::open(repo)?;
+
+    let result = resolve_rev_number_or_hex_prefix(input, &changelog.revlog);
+    if !matches!(result, Err(RevlogError::InvalidRevision)) {
+        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<Revision, RevlogError> {
+    if let Ok(integer) = input.parse::<i32>() {
+        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)
+}
diff --git a/rust/hg-core/src/revlog/revlog.rs b/rust/hg-core/src/revlog/revlog.rs
--- a/rust/hg-core/src/revlog/revlog.rs
+++ b/rust/hg-core/src/revlog/revlog.rs
@@ -144,6 +144,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 --git a/rust/hg-core/src/revlog/changelog.rs b/rust/hg-core/src/revlog/changelog.rs
--- a/rust/hg-core/src/revlog/changelog.rs
+++ b/rust/hg-core/src/revlog/changelog.rs
@@ -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 --git a/rust/hg-core/src/operations/list_tracked_files.rs b/rust/hg-core/src/operations/list_tracked_files.rs
--- a/rust/hg-core/src/operations/list_tracked_files.rs
+++ b/rust/hg-core/src/operations/list_tracked_files.rs
@@ -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<FilesForRev, ListRevTrackedFilesError> {
+    let rev = crate::revset::resolve_single(revset, repo)?;
     let changelog = Changelog::open(repo)?;
     let manifest = Manifest::open(repo)?;
-
-    let changelog_entry = match rev.parse::<Revision>() {
-        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 --git a/rust/hg-core/src/operations/debugdata.rs b/rust/hg-core/src/operations/debugdata.rs
--- a/rust/hg-core/src/operations/debugdata.rs
+++ b/rust/hg-core/src/operations/debugdata.rs
@@ -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<Vec<u8>, 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::<Revision>() {
-        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 --git a/rust/hg-core/src/operations/cat.rs b/rust/hg-core/src/operations/cat.rs
--- a/rust/hg-core/src/operations/cat.rs
+++ b/rust/hg-core/src/operations/cat.rs
@@ -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<Vec<u8>, 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::<Revision>() {
-        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 --git a/rust/hg-core/src/lib.rs b/rust/hg-core/src/lib.rs
--- a/rust/hg-core/src/lib.rs
+++ b/rust/hg-core/src/lib.rs
@@ -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};