From 46edbbef09f960c6081d26a24593d81b28b3fbff Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 25 Apr 2021 23:38:23 -0700 Subject: [PATCH] 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. --- lib/src/revset.rs | 26 ++++++++++++++++++++++++-- lib/tests/test_revset.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 3140d02c3..671270429 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -119,6 +119,7 @@ pub enum RevsetExpression { }, AllHeads, PublicHeads, + GitRefs, NonObsoleteHeads(Rc), 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 }) } diff --git a/lib/tests/test_revset.rs b/lib/tests/test_revset.rs index d529a8d87..030b312e3 100644 --- a/lib/tests/test_revset.rs +++ b/lib/tests/test_revset.rs @@ -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) {