gitoxide_core/repository/revision/
resolve.rs

1use crate::OutputFormat;
2
3pub struct Options {
4    pub format: OutputFormat,
5    pub explain: bool,
6    pub cat_file: bool,
7    pub tree_mode: TreeMode,
8    pub blob_format: BlobFormat,
9    pub show_reference: bool,
10}
11
12pub enum TreeMode {
13    Raw,
14    Pretty,
15}
16
17#[derive(Copy, Clone)]
18pub enum BlobFormat {
19    Git,
20    Worktree,
21    Diff,
22    DiffOrGit,
23}
24
25pub(crate) mod function {
26    use std::ffi::OsString;
27
28    use gix::revision::Spec;
29
30    use super::Options;
31    use crate::{
32        repository::{cat::display_object, revision, revision::resolve::BlobFormat},
33        OutputFormat,
34    };
35
36    pub fn resolve(
37        mut repo: gix::Repository,
38        specs: Vec<OsString>,
39        mut out: impl std::io::Write,
40        Options {
41            format,
42            explain,
43            cat_file,
44            tree_mode,
45            blob_format,
46            show_reference,
47        }: Options,
48    ) -> anyhow::Result<()> {
49        repo.object_cache_size_if_unset(1024 * 1024);
50        let mut cache = (!matches!(blob_format, BlobFormat::Git))
51            .then(|| {
52                repo.diff_resource_cache(
53                    match blob_format {
54                        BlobFormat::Git => {
55                            unreachable!("checked before")
56                        }
57                        BlobFormat::Worktree | BlobFormat::Diff => {
58                            gix::diff::blob::pipeline::Mode::ToWorktreeAndBinaryToText
59                        }
60                        BlobFormat::DiffOrGit => gix::diff::blob::pipeline::Mode::ToGitUnlessBinaryToTextIsPresent,
61                    },
62                    Default::default(),
63                )
64            })
65            .transpose()?;
66
67        match format {
68            OutputFormat::Human => {
69                for spec in specs {
70                    if explain {
71                        return revision::explain(spec, out);
72                    }
73                    let spec = gix::path::os_str_into_bstr(&spec)?;
74                    let spec = repo.rev_parse(spec)?;
75                    if cat_file {
76                        return display_object(&repo, spec, tree_mode, cache.as_mut().map(|c| (blob_format, c)), out);
77                    }
78                    if let Some(r) = spec.first_reference().filter(|_| show_reference) {
79                        writeln!(out, "{}", r.name)?;
80                    }
81                    if let Some(r) = spec.second_reference().filter(|_| show_reference) {
82                        writeln!(out, "{}", r.name)?;
83                    }
84                    writeln!(out, "{spec}", spec = spec.detach())?;
85                }
86            }
87            #[cfg(feature = "serde")]
88            OutputFormat::Json => {
89                if explain {
90                    anyhow::bail!("Explanations are only for human consumption")
91                }
92                serde_json::to_writer_pretty(
93                    &mut out,
94                    &specs
95                        .into_iter()
96                        .map(|spec| {
97                            gix::path::os_str_into_bstr(&spec)
98                                .map_err(anyhow::Error::from)
99                                .and_then(|spec| repo.rev_parse(spec).map_err(Into::into))
100                                .map(Spec::detach)
101                        })
102                        .collect::<Result<Vec<_>, _>>()?,
103                )?;
104            }
105        }
106        Ok(())
107    }
108}