revsets: add revset function for getting all git refs

This adds a `git_refs()` revset that includes all commits pointed to
by a git ref. It's not very useful yet because the graph log doesn't
use the right type of edges for non-contiguous commits.
This commit is contained in:
Martin von Zweigbergk 2021-04-25 23:38:23 -07:00
parent f5151bdbbe
commit 46edbbef09
2 changed files with 59 additions and 2 deletions

View file

@ -119,6 +119,7 @@ pub enum RevsetExpression {
},
AllHeads,
PublicHeads,
GitRefs,
NonObsoleteHeads(Rc<RevsetExpression>),
Description {
needle: String,
@ -410,6 +411,16 @@ fn parse_function_expression(
})
}
}
"git_refs" => {
if arg_count == 0 {
Ok(RevsetExpression::GitRefs)
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
message: "Expected 0 arguments".to_string(),
})
}
}
"description" => {
if !(1..=2).contains(&arg_count) {
return Err(RevsetParseError::InvalidFunctionArguments {
@ -726,7 +737,7 @@ pub fn evaluate_expression<'revset, 'repo: 'revset>(
let mut parent_entries: Vec<_> =
base_set.iter().flat_map(|entry| entry.parents()).collect();
parent_entries.sort_by_key(|b| Reverse(b.position()));
parent_entries.dedup_by_key(|entry| entry.position());
parent_entries.dedup();
Ok(Box::new(EagerRevset {
index_entries: parent_entries,
}))
@ -802,6 +813,18 @@ pub fn evaluate_expression<'revset, 'repo: 'revset>(
index_entries.sort_by_key(|b| Reverse(b.position()));
Ok(Box::new(EagerRevset { index_entries }))
}
RevsetExpression::GitRefs => {
let index = repo.index();
let mut index_entries: Vec<_> = repo
.view()
.git_refs()
.values()
.map(|id| index.entry_by_id(id).unwrap())
.collect();
index_entries.sort_by_key(|b| Reverse(b.position()));
index_entries.dedup();
Ok(Box::new(EagerRevset { index_entries }))
}
RevsetExpression::Description {
needle,
candidates: base_expression,
@ -870,7 +893,6 @@ fn non_obsolete_heads<'revset, 'repo: 'revset>(
.map(|id| index.entry_by_id(id).unwrap())
.collect();
index_entries.sort_by_key(|b| Reverse(b.position()));
index_entries.sort_by_key(|b| Reverse(b.position()));
Box::new(EagerRevset { index_entries })
}

View file

@ -714,6 +714,41 @@ fn test_evaluate_expression_public_heads(use_git: bool) {
tx.discard();
}
#[test_case(false ; "local store")]
#[test_case(true ; "git store")]
fn test_evaluate_expression_git_refs(use_git: bool) {
let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
let mut tx = repo.start_transaction("test");
let mut_repo = tx.mut_repo();
let commit1 = testutils::create_random_commit(&settings, &repo).write_to_repo(mut_repo);
let commit2 = testutils::create_random_commit(&settings, &repo).write_to_repo(mut_repo);
// Can get git refs when there are none
assert_eq!(
resolve_commit_ids(mut_repo.as_repo_ref(), "git_refs()"),
vec![]
);
// Can get a mix of git refs
mut_repo.insert_git_ref("refs/heads/branch1".to_string(), commit1.id().clone());
mut_repo.insert_git_ref("refs/tags/tag1".to_string(), commit2.id().clone());
assert_eq!(
resolve_commit_ids(mut_repo.as_repo_ref(), "git_refs()"),
vec![commit2.id().clone(), commit1.id().clone()]
);
// Two refs pointing to the same commit does not result in a duplicate in the
// revset
mut_repo.insert_git_ref("refs/tags/tag2".to_string(), commit2.id().clone());
assert_eq!(
resolve_commit_ids(mut_repo.as_repo_ref(), "git_refs()"),
vec![commit2.id().clone(), commit1.id().clone()]
);
tx.discard();
}
#[test_case(false ; "local store")]
#[test_case(true ; "git store")]
fn test_evaluate_expression_obsolete(use_git: bool) {