WIP: List the most recent change to each top-level entry in a git tree

improve ux

Signed-off-by: tjh <did:plc:65gha4t3avpfpzmvpbwovss7>

tjh.dev 47b84e6f 958bf8a0

verified
+20 -11
+1
Cargo.toml
··· 1 1 [package] 2 2 name = "glc" 3 3 version = "0.1.0" 4 + description = "Find the latest commit for each entry in a git tree" 4 5 authors = ["tjh <x@tjh.dev>"] 5 6 license = "MIT" 6 7 edition = "2024"
+5 -4
src/cli.rs
··· 6 6 } 7 7 8 8 #[derive(Parser)] 9 + #[command(about, author, version)] 9 10 pub struct Arguments { 10 11 /// Commit, tag, or branch to start scanning from. 11 12 #[arg(long, value_name = "from-revspec", default_value = "HEAD")] ··· 15 16 #[arg(long, value_name = "to-revspec")] 16 17 pub to: Option<String>, 17 18 18 - /// Convert timestamps to UTC. 19 + /// Preserve timezone in timestamp output. 19 20 #[arg{long}] 20 - pub utc: bool, 21 + pub preserve_tz: bool, 21 22 22 23 /// Path to the git repository. 23 - #[arg(value_hint = ValueHint::DirPath, default_value = ".")] 24 - pub repository_path: PathBuf, 24 + #[arg(long, short = 'R', value_hint = ValueHint::DirPath, default_value = ".")] 25 + pub repository: PathBuf, 25 26 26 27 pub subtree: Option<PathBuf>, 27 28 }
+14 -7
src/main.rs
··· 15 15 16 16 fn main() -> anyhow::Result<()> { 17 17 let arguments = cli::parse(); 18 - let repository = gix::open(arguments.repository_path)?; 18 + let repository = gix::open(arguments.repository)?; 19 19 20 20 let mut current_commit = repository.resolve_revspec(&arguments.from)?; 21 21 let mut current_tree = current_commit ··· 54 54 55 55 let output = |filename: &BStr, commit: &Commit| -> anyhow::Result<()> { 56 56 let id = commit.id; 57 - let ts = format_ts(&commit.time()?, arguments.utc)?; 57 + let ts = format_ts(&commit.time()?, arguments.preserve_tz)?; 58 58 let message = commit.message()?.summary(); 59 - println!("{filename:<name_pad$}\t{id}\t{ts}\t{message}",); 59 + let escaped_filename = format!("{filename:?}"); 60 + println!("{escaped_filename:<name_pad$}\t{id}\t{ts}\t{message}",); 60 61 Ok(()) 61 62 }; 62 63 ··· 104 105 } 105 106 106 107 current_commit = parent_commit; 108 + } 109 + 110 + if !interested.is_empty() { 111 + for entry in interested.drain() { 112 + println!("{:?}", entry.as_bstr()); 113 + } 107 114 } 108 115 109 116 Ok(()) ··· 216 223 } 217 224 } 218 225 219 - fn format_ts(time: &Time, utc: bool) -> anyhow::Result<String> { 226 + fn format_ts(time: &Time, preserve_tz: bool) -> anyhow::Result<String> { 220 227 use time::OffsetDateTime; 221 228 use time::UtcOffset; 222 229 use time::format_description::well_known::Rfc3339; ··· 224 231 let odt = OffsetDateTime::from_unix_timestamp(time.seconds)? 225 232 .to_offset(UtcOffset::from_whole_seconds(time.offset)?); 226 233 227 - let formatted = match utc { 228 - true => odt.to_utc().format(&Rfc3339)?, 229 - false => odt.format(&Rfc3339)?, 234 + let formatted = match preserve_tz { 235 + true => odt.format(&Rfc3339)?, 236 + false => odt.to_utc().format(&Rfc3339)?, 230 237 }; 231 238 232 239 Ok(formatted)