Skip to main content

git_spawn/command/
cat_file.rs

1//! `git cat-file` — provide content or type/size information for repository objects.
2
3use crate::command::{CommandExecutor, GitCommand};
4use crate::error::{Error, Result};
5use async_trait::async_trait;
6
7/// Mode of operation for `cat-file`.
8#[derive(Debug, Clone, Copy)]
9pub enum CatFileMode {
10    /// `-t`: print the object's type.
11    Type,
12    /// `-s`: print the object's size.
13    Size,
14    /// `-e`: exit 0 if object exists, non-zero otherwise.
15    Exists,
16    /// `-p`: pretty-print the object's contents.
17    PrettyPrint,
18}
19
20/// Builder for `git cat-file`.
21#[derive(Debug, Clone)]
22pub struct CatFileCommand {
23    /// Shared executor.
24    pub executor: CommandExecutor,
25    /// Operation mode.
26    pub mode: CatFileMode,
27    /// Object to inspect.
28    pub object: String,
29}
30
31impl CatFileCommand {
32    /// Create a `cat-file -p <object>` command.
33    pub fn pretty_print(object: impl Into<String>) -> Self {
34        Self {
35            executor: CommandExecutor::default(),
36            mode: CatFileMode::PrettyPrint,
37            object: object.into(),
38        }
39    }
40
41    /// Create a `cat-file -t <object>` command.
42    pub fn object_type(object: impl Into<String>) -> Self {
43        Self {
44            executor: CommandExecutor::default(),
45            mode: CatFileMode::Type,
46            object: object.into(),
47        }
48    }
49
50    /// Create a `cat-file -s <object>` command.
51    pub fn size(object: impl Into<String>) -> Self {
52        Self {
53            executor: CommandExecutor::default(),
54            mode: CatFileMode::Size,
55            object: object.into(),
56        }
57    }
58
59    /// Create a `cat-file -e <object>` command.
60    pub fn exists(object: impl Into<String>) -> Self {
61        Self {
62            executor: CommandExecutor::default(),
63            mode: CatFileMode::Exists,
64            object: object.into(),
65        }
66    }
67}
68
69#[async_trait]
70impl GitCommand for CatFileCommand {
71    /// Trimmed stdout. For `Exists` mode, success is reported via `Ok(String::new())`;
72    /// a missing object returns [`Error::CommandFailed`].
73    type Output = String;
74    fn get_executor(&self) -> &CommandExecutor {
75        &self.executor
76    }
77    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
78        &mut self.executor
79    }
80    fn build_command_args(&self) -> Vec<String> {
81        let flag = match self.mode {
82            CatFileMode::Type => "-t",
83            CatFileMode::Size => "-s",
84            CatFileMode::Exists => "-e",
85            CatFileMode::PrettyPrint => "-p",
86        };
87        vec!["cat-file".into(), flag.into(), self.object.clone()]
88    }
89    async fn execute(&self) -> Result<String> {
90        if self.object.is_empty() {
91            return Err(Error::invalid_config(
92                "cat-file requires a non-empty object",
93            ));
94        }
95        let out = self.execute_raw().await?;
96        Ok(out.stdout_trimmed().to_string())
97    }
98}