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