From b83f6bdf7f8d8f5cef2a57fa3932b6a0e0988db1 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 3 Aug 2022 16:46:10 +0800 Subject: [PATCH] feat: `--cat-file` flag for `gix rev parse` to cat instead of resolving. (#427) --- .../src/repository/revision/resolve.rs | 30 ++++++++++++++++--- src/plumbing/main.rs | 12 ++++++-- src/plumbing/options.rs | 6 +++- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/gitoxide-core/src/repository/revision/resolve.rs b/gitoxide-core/src/repository/revision/resolve.rs index ef4e89ebabe..d58851715c9 100644 --- a/gitoxide-core/src/repository/revision/resolve.rs +++ b/gitoxide-core/src/repository/revision/resolve.rs @@ -3,10 +3,11 @@ use crate::OutputFormat; pub struct Options { pub format: OutputFormat, pub explain: bool, + pub cat_file: bool, } pub(crate) mod function { - use anyhow::bail; + use anyhow::{bail, Context}; use std::ffi::OsString; use git_repository as git; @@ -19,7 +20,11 @@ pub(crate) mod function { mut repo: git::Repository, specs: Vec, mut out: impl std::io::Write, - Options { format, explain }: Options, + Options { + format, + explain, + cat_file, + }: Options, ) -> anyhow::Result<()> { repo.object_cache_size_if_unset(1024 * 1024); @@ -30,8 +35,11 @@ pub(crate) mod function { return revision::explain(spec, out); } let spec = git::path::os_str_into_bstr(&spec)?; - let spec = repo.rev_parse(spec)?.detach(); - writeln!(out, "{spec}")?; + let spec = repo.rev_parse(spec)?; + if cat_file { + return display_object(spec, out); + } + writeln!(out, "{spec}", spec = spec.detach())?; } } #[cfg(feature = "serde1")] @@ -55,4 +63,18 @@ pub(crate) mod function { } Ok(()) } + + fn display_object(spec: git::revision::Spec<'_>, mut out: impl std::io::Write) -> anyhow::Result<()> { + let id = spec.single().context("rev-spec must resolve to a single object")?; + let object = id.object()?; + match object.kind { + git::object::Kind::Tree => { + for entry in object.into_tree().iter() { + writeln!(out, "{}", entry?)?; + } + } + _ => out.write_all(&object.data)?, + } + Ok(()) + } } diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 029f9a071e7..7385b9d8f6f 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -532,7 +532,11 @@ pub fn main() -> Result<()> { None, move |_progress, out, _err| core::repository::revision::explain(spec, out), ), - revision::Subcommands::Resolve { specs, explain } => prepare_and_run( + revision::Subcommands::Resolve { + specs, + explain, + cat_file, + } => prepare_and_run( "revision-parse", verbose, progress, @@ -543,7 +547,11 @@ pub fn main() -> Result<()> { repository()?, specs, out, - core::repository::revision::resolve::Options { format, explain }, + core::repository::revision::resolve::Options { + format, + explain, + cat_file, + }, ) }, ), diff --git a/src/plumbing/options.rs b/src/plumbing/options.rs index ecdcb0fb736..05647f71751 100644 --- a/src/plumbing/options.rs +++ b/src/plumbing/options.rs @@ -187,10 +187,14 @@ pub mod revision { /// Try to resolve the given revspec and print the object names. #[clap(visible_alias = "query", visible_alias = "parse")] Resolve { - /// If set, instead of resolving a rev-spec, explain what would be done for the first spec. + /// Instead of resolving a rev-spec, explain what would be done for the first spec. + /// /// Equivalent to the `explain` subcommand. #[clap(short = 'e', long)] explain: bool, + /// Show the first resulting object similar to how `git cat-file` would, but don't show the resolved spec. + #[clap(short = 'c', long, conflicts_with = "explain")] + cat_file: bool, /// rev-specs like `@`, `@~1` or `HEAD^2`. #[clap(required = true)] specs: Vec,