rust/hg-core/src/revset.rs
author Simon Sapin <simon.sapin@octobus.net>
Mon, 13 Sep 2021 18:09:10 +0200
changeset 47964 796206e74b10
parent 47962 8c29af0f6d6e
child 47968 6f579618ea7b
permissions -rw-r--r--
rhg: Reuse manifest when checking status of multiple ambiguous files When `rhg status` cannot determine whether a file is clean based on mtime and size alone, it needs to compare its contents with those found in the parent commit. Previously, rhg would find the (same) manifest of that commit again for every such file. This is lifted out of the loop and reused. Differential Revision: https://phab.mercurial-scm.org/D11411

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

use crate::errors::HgError;
use crate::repo::Repo;
use crate::revlog::revlog::{Revlog, RevlogError};
use crate::revlog::NodePrefix;
use crate::revlog::{Revision, NULL_REVISION, WORKING_DIRECTORY_HEX};
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 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(
        HgError::unsupported(format!("cannot parse revset '{}'", input))
            .into(),
    )
}

/// 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)
        {
            return Ok(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.get_node_rev(prefix);
    }
    Err(RevlogError::InvalidRevision)
}