1use std::path::Path;
2use std::process::Command;
3
4pub fn run() {
5 let output = Command::new("git")
7 .args(["rev-parse", "--show-toplevel"])
8 .output()
9 .expect("Failed to get repo root");
10 let repo_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
11 let repo_name = extract_repo_name(&repo_path);
12
13 let output = Command::new("git")
15 .args(["rev-parse", "--abbrev-ref", "HEAD"])
16 .output()
17 .expect("Failed to get current branch");
18 let branch = String::from_utf8_lossy(&output.stdout).trim().to_string();
19
20 let output = Command::new("git")
22 .args(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"])
23 .output()
24 .unwrap_or_else(|_| panic!("Failed to get upstream for {branch}"));
25 let tracking_raw = String::from_utf8_lossy(&output.stdout).trim().to_string();
26 let tracking = format_tracking_branch(&tracking_raw);
27
28 let output = Command::new("git")
30 .args(["rev-list", "--left-right", "--count", "HEAD...@{u}"])
31 .output()
32 .expect("Failed to get ahead/behind count");
33 let counts = String::from_utf8_lossy(&output.stdout).trim().to_string();
34 let (ahead, behind) = parse_ahead_behind_counts(&counts);
35
36 let output = Command::new("git")
38 .args(["log", "-1", "--pretty=format:%s (%cr)"])
39 .output()
40 .expect("Failed to get last commit");
41 let last_commit = String::from_utf8_lossy(&output.stdout).trim().to_string();
42
43 let bold = console::Style::new().bold();
44
45 println!("Repo: {}", bold.apply_to(repo_name));
47 println!("Branch: {}", bold.apply_to(branch));
48 println!("Tracking: {}", bold.apply_to(tracking));
49 println!(
50 "Ahead: {} Behind: {}",
51 bold.apply_to(&ahead),
52 bold.apply_to(&behind)
53 );
54 println!("Last Commit: \"{}\"", bold.apply_to(last_commit));
55}
56
57pub fn extract_repo_name(repo_path: &str) -> String {
59 Path::new(repo_path)
60 .file_name()
61 .map(|s| s.to_string_lossy().into_owned())
62 .unwrap_or_default()
63}
64
65pub fn parse_ahead_behind_counts(counts_output: &str) -> (String, String) {
67 let mut parts = counts_output.split_whitespace();
68 let ahead = parts.next().unwrap_or("0").to_string();
69 let behind = parts.next().unwrap_or("0").to_string();
70 (ahead, behind)
71}
72
73pub fn format_tracking_branch(tracking_raw: &str) -> String {
75 if tracking_raw.is_empty() {
76 "(no upstream)".to_string()
77 } else {
78 tracking_raw.to_string()
79 }
80}