view rust/hg-core/src/revset.rs @ 51700:7f0cb9ee0534

Backout accidental publication of a large range of revisions I accidentally published 25e7f9dcad0f::bd1483fd7088, this is the inverse.
author Raphaël Gomès <rgomes@octobus.net>
date Tue, 23 Jul 2024 10:02:46 +0200
parents 4c5f6e95df84
children 652149ed64f0
line wrap: on
line source

//! The revset query language
//!
//! <https://www.mercurial-scm.org/repo/hg/help/revsets>

use crate::errors::HgError;
use crate::repo::Repo;
use crate::revlog::NodePrefix;
use crate::revlog::{Revision, NULL_REVISION, WORKING_DIRECTORY_HEX};
use crate::revlog::{Revlog, RevlogError};
use crate::Node;

/// 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 = repo.changelog()?;

    match input {
        "." => {
            let p1 = repo.dirstate_parents()?.p1;
            return changelog.revlog.rev_from_node(p1.into());
        }
        "null" => return Ok(NULL_REVISION),
        _ => {}
    }

    match resolve_rev_number_or_hex_prefix(input, &changelog.revlog) {
        Err(RevlogError::InvalidRevision) => {
            // TODO: support for the rest of the language here.
            let msg = format!("cannot parse revset '{}'", input);
            Err(HgError::unsupported(msg).into())
        }
        result => result,
    }
}

/// 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> {
    // The Python equivalent of this is part of `revsymbol` in
    // `mercurial/scmutil.py`

    if let Ok(integer) = input.parse::<i32>() {
        if integer.to_string() == input
            && integer >= 0
            && revlog.has_rev(integer.into())
        {
            // This is fine because we've just checked that the revision is
            // valid for the given revlog.
            return Ok(Revision(integer));
        }
    }
    if let Ok(prefix) = NodePrefix::from_hex(input) {
        if prefix.is_prefix_of(&Node::from_hex(WORKING_DIRECTORY_HEX).unwrap())
        {
            return Err(RevlogError::WDirUnsupported);
        }
        return revlog.rev_from_node(prefix);
    }
    Err(RevlogError::InvalidRevision)
}