Skip to main content

thin_fetch/repo/
fetch.rs

1use crate::object::Object;
2use crate::utils::as_hex;
3use crate::{Error, Execute as _, Fetch, WithError as _, bail};
4
5use super::Repo;
6
7impl Repo {
8    /// Fetch listed blobs for a given commit.
9    ///
10    /// # Errors
11    ///
12    /// Returns an error if the `fetch` command or parsing the response fails.
13    pub fn fetch_blobs(&self, oid: &str, blobs: Vec<String>) -> Result<Vec<Object>, Error> {
14        let cmd = Fetch {
15            want: blobs,
16            have: vec![oid.to_owned()],
17            filter: Some("object:type=blob".to_owned()),
18            deepen: None,
19            hash_kind: self.hash_kind,
20            include_tag: false,
21        };
22
23        let packfile = cmd.execute(self)?;
24
25        packfile.collect::<Result<_, _>>()
26    }
27
28    /// Fetch commits between `have` and `want`, optionally including blobs.
29    ///
30    /// # Errors
31    ///
32    /// Returns an error if the `fetch` command or parsing the response fails.
33    pub fn fetch_tree(&self, have: &str, want: &str, blobs: bool) -> Result<Vec<Object>, Error> {
34        let cmd = Fetch {
35            want: vec![want.to_owned()],
36            have: vec![have.to_owned()],
37            filter: if blobs {
38                None
39            } else {
40                Some("blob:none".to_owned())
41            },
42            deepen: None,
43            hash_kind: self.hash_kind,
44            include_tag: false,
45        };
46
47        let packfile = cmd.execute(self)?;
48
49        packfile.collect::<Result<_, _>>()
50    }
51
52    /// Fetch commits between `have` and `want`, parsing them into a linear history.
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if the `fetch` command fails, cannot parse the response,
57    /// or the history is not linear.
58    pub fn fetch_history_linear(
59        &mut self,
60        start: &str,
61        end: &str,
62        blobs: bool,
63    ) -> Result<Vec<String>, Error> {
64        let cmd = Fetch {
65            want: vec![end.to_owned()],
66            have: vec![start.to_owned()],
67            filter: if blobs {
68                None
69            } else {
70                Some("blob:none".to_owned())
71            },
72            deepen: None,
73            hash_kind: self.hash_kind,
74            include_tag: false,
75        };
76
77        let packfile = cmd.execute(self)?;
78
79        for obj in packfile {
80            let obj = obj.with_err_msg("could not get object")?;
81            let hash = as_hex(obj.hash().as_ref());
82
83            self.object_cache.insert(hash, obj);
84        }
85
86        let mut new_head = end.to_owned();
87        let mut commits = vec![];
88
89        loop {
90            let Some(Object::Commit(commit)) = self.object_cache.get(&new_head) else {
91                bail!("commit not found: {new_head}");
92            };
93
94            let parents = &commit.parents;
95            if parents.len() > 1 {
96                bail!("commit history non-linear");
97            }
98
99            if new_head == start {
100                break;
101            }
102            commits.push(new_head);
103
104            new_head = parents.first().with_err_msg("no parent")?.to_string();
105        }
106
107        Ok(commits)
108    }
109
110    /// Fetch shallow tree for one commit, excluding blobs.
111    ///
112    /// # Errors
113    ///
114    /// Returns an error if the `fetch` command or parsing the response fails.
115    pub fn fetch_shallow(&mut self, oid: &str) -> Result<(), Error> {
116        let cmd = Fetch {
117            want: vec![oid.to_owned()],
118            have: vec![],
119            filter: Some("blob:none".to_owned()),
120            deepen: Some(1),
121            hash_kind: self.hash_kind,
122            include_tag: false,
123        };
124
125        let packfile = cmd.execute(self)?;
126
127        for obj in packfile {
128            let obj = obj.with_err_msg("could not get object")?;
129            let hash = as_hex(obj.hash().as_ref());
130
131            self.object_cache.insert(hash, obj);
132        }
133
134        Ok(())
135    }
136}