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