Skip to main content

thin_fetch/command/
mod.rs

1//! Git protocol commands.
2//!
3//! Currently implemented:
4//!
5//! - `ls-refs`: [`LsRefs`]
6//! - `fetch`: [`Fetch`]
7
8use crate::{
9    Error, HashKind, Repo,
10    parcel::{Parcel, Section},
11};
12
13mod fetch;
14mod ls_refs;
15
16pub use fetch::Fetch;
17pub use ls_refs::LsRefs;
18
19// what
20#[allow(clippy::missing_errors_doc)]
21pub trait Execute {
22    type Output;
23
24    fn execute(&self, repo: &Repo) -> Result<Self::Output, Error>;
25}
26
27/// Wrapper to compose and send custom commands.
28///
29/// # Example
30///
31/// ```rust
32/// # use thin_fetch::command::Command;
33/// # use thin_fetch::HashKind;
34/// let cmd = Command::new("ls-refs")
35///     .agent("my-cool-program/1.0")
36///     .object_format(HashKind::Sha256)
37///     .arg("unborn");
38/// ```
39#[derive(Debug, Clone)]
40pub struct Command {
41    name: String,
42    agent: String,
43    object_format: String,
44    args: Vec<String>,
45}
46
47impl Command {
48    pub fn new<S: Into<String>>(cmd: S) -> Self {
49        Self {
50            name: cmd.into(),
51            agent: "git/2.56.0".to_owned(),
52            object_format: "sha1".to_string(),
53            args: vec![],
54        }
55    }
56
57    #[must_use]
58    pub fn agent<S: Into<String>>(mut self, agent: S) -> Self {
59        self.agent = agent.into();
60        self
61    }
62
63    #[must_use]
64    pub fn object_format(mut self, hash_kind: HashKind) -> Self {
65        self.object_format = hash_kind.to_string();
66        self
67    }
68
69    #[must_use]
70    pub fn arg<S: Into<String>>(mut self, arg: S) -> Self {
71        self.args.push(arg.into());
72        self
73    }
74
75    #[must_use]
76    pub fn args<I: IntoIterator<Item = String>>(mut self, args: I) -> Self {
77        self.args.extend(args);
78        self
79    }
80}
81
82impl From<&Command> for Parcel {
83    fn from(value: &Command) -> Self {
84        let args = value
85            .args
86            .iter()
87            .map(String::as_bytes)
88            .map(<[u8]>::to_vec)
89            .collect();
90
91        Parcel::new(vec![
92            Section::new(vec![
93                format!("command={}\n", value.name).into_bytes(),
94                format!("agent={}", value.agent).into_bytes(),
95                format!("object-format={}", value.object_format).into_bytes(),
96            ]),
97            Section::new(args),
98        ])
99    }
100}
101
102impl Execute for Command {
103    type Output = Parcel;
104
105    fn execute(&self, repo: &Repo) -> Result<Self::Output, Error> {
106        repo.call(self)
107    }
108}