use std::io::Write;
use clap::Parser;
use mkit_core::refs;
use crate::clap_shim;
use crate::exit;
use crate::format;
#[derive(Debug, Parser)]
#[command(name = "mkit show-ref", about = "List refs and their object ids.")]
struct ShowRefOpts {
#[arg(long)]
heads: bool,
#[arg(long)]
tags: bool,
}
#[must_use]
pub fn run(args: &[String]) -> u8 {
let opts = match clap_shim::parse::<ShowRefOpts>("mkit show-ref", args) {
Ok(o) => o,
Err(code) => return code,
};
let cwd = match std::env::current_dir() {
Ok(p) => p,
Err(e) => return emit_err(&format!("cwd: {e}"), exit::NOINPUT),
};
let layout = match super::resolve_layout(&cwd) {
Ok(layout) => layout,
Err(code) => return code,
};
let want_heads = opts.heads || !opts.tags;
let want_tags = opts.tags || !opts.heads;
let mut lines: Vec<(String, String)> = Vec::new(); if want_heads {
match refs::list_refs(&layout) {
Ok(rs) => collect(&mut lines, &rs, "refs/heads/"),
Err(e) => return emit_err(&format!("list refs: {e}"), exit::GENERAL_ERROR),
}
}
if want_tags {
match refs::list_tags(&layout) {
Ok(rs) => collect(&mut lines, &rs, "refs/tags/"),
Err(e) => return emit_err(&format!("list tags: {e}"), exit::GENERAL_ERROR),
}
}
if !opts.heads && !opts.tags {
match refs::list_remote_names(&layout) {
Ok(remotes) => {
for remote in remotes {
match refs::list_remote_refs(&layout, &remote) {
Ok(rs) => {
collect(&mut lines, &rs, &format!("refs/remotes/{remote}/"));
}
Err(e) => {
return emit_err(
&format!("list remote refs: {e}"),
exit::GENERAL_ERROR,
);
}
}
}
}
Err(e) => return emit_err(&format!("list remotes: {e}"), exit::GENERAL_ERROR),
}
}
lines.sort_by(|a, b| a.0.cmp(&b.0));
let mut stdout = std::io::stdout().lock();
for (name, hash) in &lines {
let _ = writeln!(stdout, "{hash} {name}");
}
if lines.is_empty() {
exit::GENERAL_ERROR
} else {
exit::OK
}
}
fn collect(out: &mut Vec<(String, String)>, rs: &[refs::Ref], prefix: &str) {
for r in rs {
if let Some(h) = &r.hash {
out.push((format!("{prefix}{}", r.name), format::hex_hash(h)));
}
}
}
use super::error as emit_err;