mkit_cli/commands/
show_ref.rs1use std::io::Write;
6
7use clap::Parser;
8use mkit_core::refs;
9
10use crate::clap_shim;
11use crate::exit;
12use crate::format;
13
14#[derive(Debug, Parser)]
15#[command(name = "mkit show-ref", about = "List refs and their object ids.")]
16struct ShowRefOpts {
17 #[arg(long)]
19 heads: bool,
20 #[arg(long)]
22 tags: bool,
23}
24
25#[must_use]
26pub fn run(args: &[String]) -> u8 {
27 let opts = match clap_shim::parse::<ShowRefOpts>("mkit show-ref", args) {
28 Ok(o) => o,
29 Err(code) => return code,
30 };
31 let cwd = match std::env::current_dir() {
32 Ok(p) => p,
33 Err(e) => return emit_err(&format!("cwd: {e}"), exit::NOINPUT),
34 };
35 let mkit_dir = cwd.join(mkit_core::MKIT_DIR);
36
37 let want_heads = opts.heads || !opts.tags;
40 let want_tags = opts.tags || !opts.heads;
41
42 let mut lines: Vec<(String, String)> = Vec::new(); if want_heads {
44 match refs::list_refs(&mkit_dir) {
45 Ok(rs) => collect(&mut lines, &rs, "refs/heads/"),
46 Err(e) => return emit_err(&format!("list refs: {e}"), exit::GENERAL_ERROR),
47 }
48 }
49 if want_tags {
50 match refs::list_tags(&mkit_dir) {
51 Ok(rs) => collect(&mut lines, &rs, "refs/tags/"),
52 Err(e) => return emit_err(&format!("list tags: {e}"), exit::GENERAL_ERROR),
53 }
54 }
55 if !opts.heads && !opts.tags {
58 match refs::list_remote_names(&mkit_dir) {
59 Ok(remotes) => {
60 for remote in remotes {
61 match refs::list_remote_refs(&mkit_dir, &remote) {
62 Ok(rs) => {
63 collect(&mut lines, &rs, &format!("refs/remotes/{remote}/"));
64 }
65 Err(e) => {
66 return emit_err(
67 &format!("list remote refs: {e}"),
68 exit::GENERAL_ERROR,
69 );
70 }
71 }
72 }
73 }
74 Err(e) => return emit_err(&format!("list remotes: {e}"), exit::GENERAL_ERROR),
75 }
76 }
77 lines.sort_by(|a, b| a.0.cmp(&b.0));
78
79 let mut stdout = std::io::stdout().lock();
80 for (name, hash) in &lines {
81 let _ = writeln!(stdout, "{hash} {name}");
82 }
83 if lines.is_empty() {
86 exit::GENERAL_ERROR
87 } else {
88 exit::OK
89 }
90}
91
92fn collect(out: &mut Vec<(String, String)>, rs: &[refs::Ref], prefix: &str) {
94 for r in rs {
95 if let Some(h) = &r.hash {
96 out.push((format!("{prefix}{}", r.name), format::hex_hash(h)));
97 }
98 }
99}
100
101fn emit_err(msg: &str, code: u8) -> u8 {
102 let mut stderr = std::io::stderr().lock();
103 let _ = writeln!(stderr, "error: {msg}");
104 code
105}