gitoxide_core/repository/revision/
resolve.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::OutputFormat;

pub struct Options {
    pub format: OutputFormat,
    pub explain: bool,
    pub cat_file: bool,
    pub tree_mode: TreeMode,
    pub blob_format: BlobFormat,
    pub show_reference: bool,
}

pub enum TreeMode {
    Raw,
    Pretty,
}

#[derive(Copy, Clone)]
pub enum BlobFormat {
    Git,
    Worktree,
    Diff,
    DiffOrGit,
}

pub(crate) mod function {
    use std::ffi::OsString;

    use gix::revision::Spec;

    use super::Options;
    use crate::repository::cat::display_object;
    use crate::repository::revision::resolve::BlobFormat;
    use crate::{repository::revision, OutputFormat};

    pub fn resolve(
        mut repo: gix::Repository,
        specs: Vec<OsString>,
        mut out: impl std::io::Write,
        Options {
            format,
            explain,
            cat_file,
            tree_mode,
            blob_format,
            show_reference,
        }: Options,
    ) -> anyhow::Result<()> {
        repo.object_cache_size_if_unset(1024 * 1024);
        let mut cache = (!matches!(blob_format, BlobFormat::Git))
            .then(|| {
                repo.diff_resource_cache(
                    match blob_format {
                        BlobFormat::Git => {
                            unreachable!("checked before")
                        }
                        BlobFormat::Worktree | BlobFormat::Diff => {
                            gix::diff::blob::pipeline::Mode::ToWorktreeAndBinaryToText
                        }
                        BlobFormat::DiffOrGit => gix::diff::blob::pipeline::Mode::ToGitUnlessBinaryToTextIsPresent,
                    },
                    Default::default(),
                )
            })
            .transpose()?;

        match format {
            OutputFormat::Human => {
                for spec in specs {
                    if explain {
                        return revision::explain(spec, out);
                    }
                    let spec = gix::path::os_str_into_bstr(&spec)?;
                    let spec = repo.rev_parse(spec)?;
                    if cat_file {
                        return display_object(&repo, spec, tree_mode, cache.as_mut().map(|c| (blob_format, c)), out);
                    }
                    if let Some(r) = spec.first_reference().filter(|_| show_reference) {
                        writeln!(out, "{}", r.name)?;
                    }
                    if let Some(r) = spec.second_reference().filter(|_| show_reference) {
                        writeln!(out, "{}", r.name)?;
                    }
                    writeln!(out, "{spec}", spec = spec.detach())?;
                }
            }
            #[cfg(feature = "serde")]
            OutputFormat::Json => {
                if explain {
                    anyhow::bail!("Explanations are only for human consumption")
                }
                serde_json::to_writer_pretty(
                    &mut out,
                    &specs
                        .into_iter()
                        .map(|spec| {
                            gix::path::os_str_into_bstr(&spec)
                                .map_err(anyhow::Error::from)
                                .and_then(|spec| repo.rev_parse(spec).map_err(Into::into))
                                .map(Spec::detach)
                        })
                        .collect::<Result<Vec<_>, _>>()?,
                )?;
            }
        }
        Ok(())
    }
}