mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-18 10:07:28 +00:00
revset: move resolve_symbol() back to revset module
The only caller is now in `revset.rs`.
This commit is contained in:
parent
94aec90bee
commit
d971148e4e
3 changed files with 149 additions and 151 deletions
|
@ -18,14 +18,11 @@ use std::iter::Peekable;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::backend::{BackendError, CommitId, ObjectId};
|
use crate::backend::CommitId;
|
||||||
use crate::commit::Commit;
|
use crate::commit::Commit;
|
||||||
use crate::default_index_store::IndexEntry;
|
use crate::default_index_store::IndexEntry;
|
||||||
use crate::default_revset_graph_iterator::RevsetGraphIterator;
|
use crate::default_revset_graph_iterator::RevsetGraphIterator;
|
||||||
use crate::hex_util::to_forward_hex;
|
|
||||||
use crate::index::{HexPrefix, PrefixResolution};
|
|
||||||
use crate::matchers::{EverythingMatcher, Matcher, PrefixMatcher};
|
use crate::matchers::{EverythingMatcher, Matcher, PrefixMatcher};
|
||||||
use crate::op_store::WorkspaceId;
|
|
||||||
use crate::repo::Repo;
|
use crate::repo::Repo;
|
||||||
use crate::revset::{
|
use crate::revset::{
|
||||||
Revset, RevsetError, RevsetExpression, RevsetFilterPredicate, RevsetGraphEdge,
|
Revset, RevsetError, RevsetExpression, RevsetFilterPredicate, RevsetGraphEdge,
|
||||||
|
@ -33,147 +30,6 @@ use crate::revset::{
|
||||||
};
|
};
|
||||||
use crate::rewrite;
|
use crate::rewrite;
|
||||||
|
|
||||||
fn resolve_git_ref(repo: &dyn Repo, symbol: &str) -> Option<Vec<CommitId>> {
|
|
||||||
let view = repo.view();
|
|
||||||
for git_ref_prefix in &["", "refs/", "refs/heads/", "refs/tags/", "refs/remotes/"] {
|
|
||||||
if let Some(ref_target) = view.git_refs().get(&(git_ref_prefix.to_string() + symbol)) {
|
|
||||||
return Some(ref_target.adds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_branch(repo: &dyn Repo, symbol: &str) -> Option<Vec<CommitId>> {
|
|
||||||
if let Some(branch_target) = repo.view().branches().get(symbol) {
|
|
||||||
return Some(
|
|
||||||
branch_target
|
|
||||||
.local_target
|
|
||||||
.as_ref()
|
|
||||||
.map(|target| target.adds())
|
|
||||||
.unwrap_or_default(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if let Some((name, remote_name)) = symbol.split_once('@') {
|
|
||||||
if let Some(branch_target) = repo.view().branches().get(name) {
|
|
||||||
if let Some(target) = branch_target.remote_targets.get(remote_name) {
|
|
||||||
return Some(target.adds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_full_commit_id(
|
|
||||||
repo: &dyn Repo,
|
|
||||||
symbol: &str,
|
|
||||||
) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
|
||||||
if let Ok(binary_commit_id) = hex::decode(symbol) {
|
|
||||||
if repo.store().commit_id_length() != binary_commit_id.len() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let commit_id = CommitId::new(binary_commit_id);
|
|
||||||
match repo.store().get_commit(&commit_id) {
|
|
||||||
// Only recognize a commit if we have indexed it
|
|
||||||
Ok(_) if repo.index().entry_by_id(&commit_id).is_some() => Ok(Some(vec![commit_id])),
|
|
||||||
Ok(_) | Err(BackendError::ObjectNotFound { .. }) => Ok(None),
|
|
||||||
Err(err) => Err(RevsetError::StoreError(err)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_short_commit_id(
|
|
||||||
repo: &dyn Repo,
|
|
||||||
symbol: &str,
|
|
||||||
) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
|
||||||
if let Some(prefix) = HexPrefix::new(symbol) {
|
|
||||||
match repo.index().resolve_prefix(&prefix) {
|
|
||||||
PrefixResolution::NoMatch => Ok(None),
|
|
||||||
PrefixResolution::AmbiguousMatch => {
|
|
||||||
Err(RevsetError::AmbiguousIdPrefix(symbol.to_owned()))
|
|
||||||
}
|
|
||||||
PrefixResolution::SingleMatch(commit_id) => Ok(Some(vec![commit_id])),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_change_id(repo: &dyn Repo, symbol: &str) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
|
||||||
if let Some(prefix) = to_forward_hex(symbol).as_deref().and_then(HexPrefix::new) {
|
|
||||||
match repo.resolve_change_id_prefix(&prefix) {
|
|
||||||
PrefixResolution::NoMatch => Ok(None),
|
|
||||||
PrefixResolution::AmbiguousMatch => {
|
|
||||||
Err(RevsetError::AmbiguousIdPrefix(symbol.to_owned()))
|
|
||||||
}
|
|
||||||
PrefixResolution::SingleMatch(entries) => {
|
|
||||||
Ok(Some(entries.iter().map(|e| e.commit_id()).collect()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_symbol(
|
|
||||||
repo: &dyn Repo,
|
|
||||||
symbol: &str,
|
|
||||||
workspace_id: Option<&WorkspaceId>,
|
|
||||||
) -> Result<Vec<CommitId>, RevsetError> {
|
|
||||||
if symbol.ends_with('@') {
|
|
||||||
let target_workspace = if symbol == "@" {
|
|
||||||
if let Some(workspace_id) = workspace_id {
|
|
||||||
workspace_id.clone()
|
|
||||||
} else {
|
|
||||||
return Err(RevsetError::NoSuchRevision(symbol.to_owned()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WorkspaceId::new(symbol.strip_suffix('@').unwrap().to_string())
|
|
||||||
};
|
|
||||||
if let Some(commit_id) = repo.view().get_wc_commit_id(&target_workspace) {
|
|
||||||
Ok(vec![commit_id.clone()])
|
|
||||||
} else {
|
|
||||||
Err(RevsetError::NoSuchRevision(symbol.to_owned()))
|
|
||||||
}
|
|
||||||
} else if symbol == "root" {
|
|
||||||
Ok(vec![repo.store().root_commit_id().clone()])
|
|
||||||
} else {
|
|
||||||
// Try to resolve as a tag
|
|
||||||
if let Some(target) = repo.view().tags().get(symbol) {
|
|
||||||
return Ok(target.adds());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to resolve as a branch
|
|
||||||
if let Some(ids) = resolve_branch(repo, symbol) {
|
|
||||||
return Ok(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to resolve as a git ref
|
|
||||||
if let Some(ids) = resolve_git_ref(repo, symbol) {
|
|
||||||
return Ok(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to resolve as a full commit id. We assume a full commit id is unambiguous
|
|
||||||
// even if it's shorter than change id.
|
|
||||||
if let Some(ids) = resolve_full_commit_id(repo, symbol)? {
|
|
||||||
return Ok(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to resolve as a commit id.
|
|
||||||
if let Some(ids) = resolve_short_commit_id(repo, symbol)? {
|
|
||||||
return Ok(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to resolve as a change id.
|
|
||||||
if let Some(ids) = resolve_change_id(repo, symbol)? {
|
|
||||||
return Ok(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(RevsetError::NoSuchRevision(symbol.to_owned()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ToPredicateFn<'index> {
|
trait ToPredicateFn<'index> {
|
||||||
/// Creates function that tests if the given entry is included in the set.
|
/// Creates function that tests if the given entry is included in the set.
|
||||||
///
|
///
|
||||||
|
@ -852,7 +708,7 @@ fn has_diff_from_parent(repo: &dyn Repo, entry: &IndexEntry<'_>, matcher: &dyn M
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::backend::{ChangeId, CommitId};
|
use crate::backend::{ChangeId, CommitId, ObjectId};
|
||||||
use crate::default_index_store::MutableIndexImpl;
|
use crate::default_index_store::MutableIndexImpl;
|
||||||
use crate::index::Index;
|
use crate::index::Index;
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,11 @@ use pest::Parser;
|
||||||
use pest_derive::Parser;
|
use pest_derive::Parser;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::backend::{BackendError, BackendResult, CommitId};
|
use crate::backend::{BackendError, BackendResult, CommitId, ObjectId};
|
||||||
use crate::commit::Commit;
|
use crate::commit::Commit;
|
||||||
use crate::default_index_store::{IndexEntry, IndexPosition};
|
use crate::default_index_store::{IndexEntry, IndexPosition};
|
||||||
use crate::default_revset_engine::resolve_symbol;
|
use crate::hex_util::to_forward_hex;
|
||||||
|
use crate::index::{HexPrefix, PrefixResolution};
|
||||||
use crate::op_store::WorkspaceId;
|
use crate::op_store::WorkspaceId;
|
||||||
use crate::repo::Repo;
|
use crate::repo::Repo;
|
||||||
use crate::repo_path::{FsPathParseError, RepoPath};
|
use crate::repo_path::{FsPathParseError, RepoPath};
|
||||||
|
@ -1391,6 +1392,147 @@ pub fn optimize(expression: Rc<RevsetExpression>) -> Rc<RevsetExpression> {
|
||||||
fold_difference(&expression).unwrap_or(expression)
|
fold_difference(&expression).unwrap_or(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_git_ref(repo: &dyn Repo, symbol: &str) -> Option<Vec<CommitId>> {
|
||||||
|
let view = repo.view();
|
||||||
|
for git_ref_prefix in &["", "refs/", "refs/heads/", "refs/tags/", "refs/remotes/"] {
|
||||||
|
if let Some(ref_target) = view.git_refs().get(&(git_ref_prefix.to_string() + symbol)) {
|
||||||
|
return Some(ref_target.adds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_branch(repo: &dyn Repo, symbol: &str) -> Option<Vec<CommitId>> {
|
||||||
|
if let Some(branch_target) = repo.view().branches().get(symbol) {
|
||||||
|
return Some(
|
||||||
|
branch_target
|
||||||
|
.local_target
|
||||||
|
.as_ref()
|
||||||
|
.map(|target| target.adds())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some((name, remote_name)) = symbol.split_once('@') {
|
||||||
|
if let Some(branch_target) = repo.view().branches().get(name) {
|
||||||
|
if let Some(target) = branch_target.remote_targets.get(remote_name) {
|
||||||
|
return Some(target.adds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_full_commit_id(
|
||||||
|
repo: &dyn Repo,
|
||||||
|
symbol: &str,
|
||||||
|
) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
||||||
|
if let Ok(binary_commit_id) = hex::decode(symbol) {
|
||||||
|
if repo.store().commit_id_length() != binary_commit_id.len() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let commit_id = CommitId::new(binary_commit_id);
|
||||||
|
match repo.store().get_commit(&commit_id) {
|
||||||
|
// Only recognize a commit if we have indexed it
|
||||||
|
Ok(_) if repo.index().entry_by_id(&commit_id).is_some() => Ok(Some(vec![commit_id])),
|
||||||
|
Ok(_) | Err(BackendError::ObjectNotFound { .. }) => Ok(None),
|
||||||
|
Err(err) => Err(RevsetError::StoreError(err)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_short_commit_id(
|
||||||
|
repo: &dyn Repo,
|
||||||
|
symbol: &str,
|
||||||
|
) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
||||||
|
if let Some(prefix) = HexPrefix::new(symbol) {
|
||||||
|
match repo.index().resolve_prefix(&prefix) {
|
||||||
|
PrefixResolution::NoMatch => Ok(None),
|
||||||
|
PrefixResolution::AmbiguousMatch => {
|
||||||
|
Err(RevsetError::AmbiguousIdPrefix(symbol.to_owned()))
|
||||||
|
}
|
||||||
|
PrefixResolution::SingleMatch(commit_id) => Ok(Some(vec![commit_id])),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_change_id(repo: &dyn Repo, symbol: &str) -> Result<Option<Vec<CommitId>>, RevsetError> {
|
||||||
|
if let Some(prefix) = to_forward_hex(symbol).as_deref().and_then(HexPrefix::new) {
|
||||||
|
match repo.resolve_change_id_prefix(&prefix) {
|
||||||
|
PrefixResolution::NoMatch => Ok(None),
|
||||||
|
PrefixResolution::AmbiguousMatch => {
|
||||||
|
Err(RevsetError::AmbiguousIdPrefix(symbol.to_owned()))
|
||||||
|
}
|
||||||
|
PrefixResolution::SingleMatch(entries) => {
|
||||||
|
Ok(Some(entries.iter().map(|e| e.commit_id()).collect()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_symbol(
|
||||||
|
repo: &dyn Repo,
|
||||||
|
symbol: &str,
|
||||||
|
workspace_id: Option<&WorkspaceId>,
|
||||||
|
) -> Result<Vec<CommitId>, RevsetError> {
|
||||||
|
if symbol.ends_with('@') {
|
||||||
|
let target_workspace = if symbol == "@" {
|
||||||
|
if let Some(workspace_id) = workspace_id {
|
||||||
|
workspace_id.clone()
|
||||||
|
} else {
|
||||||
|
return Err(RevsetError::NoSuchRevision(symbol.to_owned()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WorkspaceId::new(symbol.strip_suffix('@').unwrap().to_string())
|
||||||
|
};
|
||||||
|
if let Some(commit_id) = repo.view().get_wc_commit_id(&target_workspace) {
|
||||||
|
Ok(vec![commit_id.clone()])
|
||||||
|
} else {
|
||||||
|
Err(RevsetError::NoSuchRevision(symbol.to_owned()))
|
||||||
|
}
|
||||||
|
} else if symbol == "root" {
|
||||||
|
Ok(vec![repo.store().root_commit_id().clone()])
|
||||||
|
} else {
|
||||||
|
// Try to resolve as a tag
|
||||||
|
if let Some(target) = repo.view().tags().get(symbol) {
|
||||||
|
return Ok(target.adds());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to resolve as a branch
|
||||||
|
if let Some(ids) = resolve_branch(repo, symbol) {
|
||||||
|
return Ok(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to resolve as a git ref
|
||||||
|
if let Some(ids) = resolve_git_ref(repo, symbol) {
|
||||||
|
return Ok(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to resolve as a full commit id. We assume a full commit id is unambiguous
|
||||||
|
// even if it's shorter than change id.
|
||||||
|
if let Some(ids) = resolve_full_commit_id(repo, symbol)? {
|
||||||
|
return Ok(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to resolve as a commit id.
|
||||||
|
if let Some(ids) = resolve_short_commit_id(repo, symbol)? {
|
||||||
|
return Ok(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to resolve as a change id.
|
||||||
|
if let Some(ids) = resolve_change_id(repo, symbol)? {
|
||||||
|
return Ok(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(RevsetError::NoSuchRevision(symbol.to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Maybe return a new type (RevsetParameters?) instead of
|
// TODO: Maybe return a new type (RevsetParameters?) instead of
|
||||||
// RevsetExpression. Then pass that to evaluate(), so it's clear which variants
|
// RevsetExpression. Then pass that to evaluate(), so it's clear which variants
|
||||||
// are allowed.
|
// are allowed.
|
||||||
|
|
|
@ -17,14 +17,14 @@ use std::path::Path;
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use jujutsu_lib::backend::{CommitId, MillisSinceEpoch, ObjectId, Signature, Timestamp};
|
use jujutsu_lib::backend::{CommitId, MillisSinceEpoch, ObjectId, Signature, Timestamp};
|
||||||
use jujutsu_lib::default_revset_engine::{resolve_symbol, revset_for_commits};
|
use jujutsu_lib::default_revset_engine::revset_for_commits;
|
||||||
use jujutsu_lib::git;
|
use jujutsu_lib::git;
|
||||||
use jujutsu_lib::op_store::{RefTarget, WorkspaceId};
|
use jujutsu_lib::op_store::{RefTarget, WorkspaceId};
|
||||||
use jujutsu_lib::repo::Repo;
|
use jujutsu_lib::repo::Repo;
|
||||||
use jujutsu_lib::repo_path::RepoPath;
|
use jujutsu_lib::repo_path::RepoPath;
|
||||||
use jujutsu_lib::revset::{
|
use jujutsu_lib::revset::{
|
||||||
optimize, parse, resolve_symbols, ReverseRevsetGraphIterator, RevsetAliasesMap, RevsetError,
|
optimize, parse, resolve_symbol, resolve_symbols, ReverseRevsetGraphIterator, RevsetAliasesMap,
|
||||||
RevsetExpression, RevsetFilterPredicate, RevsetGraphEdge, RevsetIteratorExt,
|
RevsetError, RevsetExpression, RevsetFilterPredicate, RevsetGraphEdge, RevsetIteratorExt,
|
||||||
RevsetWorkspaceContext,
|
RevsetWorkspaceContext,
|
||||||
};
|
};
|
||||||
use jujutsu_lib::settings::GitSettings;
|
use jujutsu_lib::settings::GitSettings;
|
||||||
|
|
Loading…
Reference in a new issue