tame_index/index/
git.rs

1use super::{FileLock, IndexCache};
2use crate::{Error, IndexKrate, KrateName, PathBuf};
3
4/// The URL of the crates.io index for use with git
5pub const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index";
6
7/// Allows access to a cargo git registry index
8///
9/// Uses Cargo's cache.
10pub struct GitIndex {
11    pub(super) cache: IndexCache,
12    #[allow(dead_code)]
13    pub(super) url: String,
14    /// The sha-1 head commit id encoded as hex
15    pub head: Option<[u8; 40]>,
16}
17
18impl GitIndex {
19    /// Creates a new git index for the specified location
20    #[inline]
21    pub fn new(il: crate::index::IndexLocation<'_>) -> Result<Self, Error> {
22        if il.url.is_sparse() {
23            return Err(crate::InvalidUrl {
24                url: il.url.as_str().to_owned(),
25                source: crate::InvalidUrlError::SparseForGit,
26            }
27            .into());
28        }
29
30        let (path, url) = il.into_parts()?;
31        Ok(Self {
32            cache: IndexCache::at_path(path),
33            url,
34            head: None,
35        })
36    }
37
38    /// Sets the sha-1 id for the head commit.
39    ///
40    /// If set, this will be used to disregard cache entries that do not match
41    #[inline]
42    pub fn set_head_commit(&mut self, commit_id: Option<[u8; 20]>) {
43        if let Some(id) = &commit_id {
44            let mut hex_head = [0u8; 40];
45            crate::utils::encode_hex(id, &mut hex_head);
46            self.head = Some(hex_head);
47        } else {
48            self.head = None;
49        }
50    }
51
52    /// Gets the hex-encoded sha-1 id for the head commit
53    #[inline]
54    pub fn head_commit(&self) -> Option<&str> {
55        self.head.as_ref().map(|hc| {
56            // SAFETY: the buffer is always ASCII hex
57            #[allow(unsafe_code)]
58            unsafe {
59                std::str::from_utf8_unchecked(hc)
60            }
61        })
62    }
63
64    /// Reads a crate from the local cache of the index.
65    ///
66    /// There are no guarantees around freshness, and no network I/O will be
67    /// performed.
68    #[inline]
69    pub fn cached_krate(
70        &self,
71        name: KrateName<'_>,
72        lock: &FileLock,
73    ) -> Result<Option<IndexKrate>, Error> {
74        self.cache.cached_krate(name, self.head_commit(), lock)
75    }
76
77    /// Writes the specified crate to the cache.
78    ///
79    /// Note that no I/O will be performed if `blob_id` or [`Self::set_head_commit`]
80    /// has not been set to `Some`
81    #[inline]
82    pub fn write_to_cache(
83        &self,
84        krate: &IndexKrate,
85        blob_id: Option<&str>,
86        lock: &FileLock,
87    ) -> Result<Option<PathBuf>, Error> {
88        let Some(id) = blob_id.or_else(|| self.head_commit()) else {
89            return Ok(None);
90        };
91        self.cache.write_to_cache(krate, id, lock).map(Some)
92    }
93}