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
--- 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};
--- 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<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![];
--- 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<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)
}
--- 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<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())?;
--- 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 {
--- 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
--- /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
+//!
+//! <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)?;
+
+ 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<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)
+}