git_branchless_query/
lib.rs1use std::fmt::Write;
2
3use git_branchless_invoke::CommandContext;
4use itertools::Itertools;
5use lib::core::dag::Dag;
6use lib::core::effects::{Effects, OperationType};
7use lib::core::eventlog::{EventLogDb, EventReplayer};
8use lib::core::repo_ext::RepoExt;
9use lib::git::{CategorizedReferenceName, GitRunInfo, Repo};
10use lib::util::{ExitCode, EyreExitOr};
11use tracing::instrument;
12
13use git_branchless_opts::{QueryArgs, ResolveRevsetOptions, Revset};
14use git_branchless_revset::resolve_commits;
15
16#[instrument]
18pub fn command_main(ctx: CommandContext, args: QueryArgs) -> EyreExitOr<()> {
19 let CommandContext {
20 effects,
21 git_run_info,
22 } = ctx;
23 let QueryArgs {
24 revset,
25 resolve_revset_options,
26 show_branches,
27 raw,
28 } = args;
29 query(
30 &effects,
31 &git_run_info,
32 revset,
33 &resolve_revset_options,
34 show_branches,
35 raw,
36 )
37}
38
39#[instrument]
40fn query(
41 effects: &Effects,
42 git_run_info: &GitRunInfo,
43 query: Revset,
44 resolve_revset_options: &ResolveRevsetOptions,
45 show_branches: bool,
46 raw: bool,
47) -> EyreExitOr<()> {
48 let repo = Repo::from_current_dir()?;
49 let conn = repo.get_db_conn()?;
50 let event_log_db = EventLogDb::new(&conn)?;
51 let event_replayer = EventReplayer::from_event_log_db(effects, &repo, &event_log_db)?;
52 let event_cursor = event_replayer.make_default_cursor();
53 let references_snapshot = repo.get_references_snapshot()?;
54 let mut dag = Dag::open_and_sync(
55 effects,
56 &repo,
57 &event_replayer,
58 event_cursor,
59 &references_snapshot,
60 )?;
61
62 let commit_set =
63 match resolve_commits(effects, &repo, &mut dag, &[query], resolve_revset_options) {
64 Ok(commit_sets) => commit_sets[0].clone(),
65 Err(err) => {
66 err.describe(effects)?;
67 return Ok(Err(ExitCode(1)));
68 }
69 };
70
71 if show_branches {
72 let commit_oids = {
73 let (effects, _progress) = effects.start_operation(OperationType::SortCommits);
74 let _effects = effects;
75
76 let commit_set = commit_set.intersection(&dag.branch_commits);
77 dag.sort(&commit_set)?
78 };
79 let ref_names = commit_oids
80 .into_iter()
81 .flat_map(
82 |oid| match references_snapshot.branch_oid_to_names.get(&oid) {
83 Some(branch_names) => branch_names.iter().sorted().collect_vec(),
84 None => Vec::new(),
85 },
86 )
87 .collect_vec();
88 for ref_name in ref_names {
89 let ref_name = CategorizedReferenceName::new(ref_name);
90 writeln!(effects.get_output_stream(), "{}", ref_name.render_suffix())?;
91 }
92 } else {
93 let commit_oids = {
94 let (effects, _progress) = effects.start_operation(OperationType::SortCommits);
95 let _effects = effects;
96 dag.sort(&commit_set)?
97 };
98 for commit_oid in commit_oids {
99 if raw {
100 writeln!(effects.get_output_stream(), "{commit_oid}")?;
101 } else {
102 let commit = repo.find_commit_or_fail(commit_oid)?;
103 writeln!(
104 effects.get_output_stream(),
105 "{}",
106 effects
107 .get_glyphs()
108 .render(commit.friendly_describe(effects.get_glyphs())?)?,
109 )?;
110 }
111 }
112 }
113
114 Ok(Ok(()))
115}