mkit_cli/commands/
merge_base.rs1use std::io::Write;
8
9use clap::Parser;
10use mkit_core::ops::merge::{find_merge_base, is_ancestor};
11use mkit_core::store::ObjectStore;
12
13use crate::clap_shim;
14use crate::exit;
15use crate::format;
16
17#[derive(Debug, Parser)]
18#[command(
19 name = "mkit merge-base",
20 about = "Find a common ancestor of two commits."
21)]
22struct MergeBaseOpts {
23 #[arg(long = "is-ancestor")]
26 is_ancestor: bool,
27 a: String,
28 b: String,
29}
30
31#[must_use]
32pub fn run(args: &[String]) -> u8 {
33 let opts = match clap_shim::parse::<MergeBaseOpts>("mkit merge-base", args) {
34 Ok(o) => o,
35 Err(code) => return code,
36 };
37 let cwd = match std::env::current_dir() {
38 Ok(p) => p,
39 Err(e) => return emit_err(&format!("cwd: {e}"), exit::NOINPUT),
40 };
41 let layout = match super::resolve_layout(&cwd) {
42 Ok(layout) => layout,
43 Err(code) => return code,
44 };
45 let store = match ObjectStore::open(&layout) {
46 Ok(s) => s,
47 Err(e) => return emit_err(&format!("not a mkit repo: {e}"), exit::GENERAL_ERROR),
48 };
49 let a = match super::revspec::resolve_revision(&store, &layout, &opts.a) {
52 Ok(h) => super::log::peel_tags(&store, h),
53 Err(e) => {
54 return emit_err(
55 &format!("bad revision '{}': {e}", opts.a),
56 exit::GENERAL_ERROR,
57 );
58 }
59 };
60 let b = match super::revspec::resolve_revision(&store, &layout, &opts.b) {
61 Ok(h) => super::log::peel_tags(&store, h),
62 Err(e) => {
63 return emit_err(
64 &format!("bad revision '{}': {e}", opts.b),
65 exit::GENERAL_ERROR,
66 );
67 }
68 };
69
70 if opts.is_ancestor {
71 return match is_ancestor(&store, a, b) {
72 Ok(true) => exit::OK,
73 Ok(false) => exit::GENERAL_ERROR,
74 Err(e) => emit_err(&format!("merge-base: {e}"), exit::GENERAL_ERROR),
75 };
76 }
77
78 match find_merge_base(&store, a, b) {
79 Ok(Some(base)) => {
80 let mut stdout = std::io::stdout().lock();
81 let _ = writeln!(stdout, "{}", format::hex_hash(&base));
82 exit::OK
83 }
84 Ok(None) => exit::GENERAL_ERROR,
86 Err(e) => emit_err(&format!("merge-base: {e}"), exit::GENERAL_ERROR),
87 }
88}
89
90use super::error as emit_err;