margo_fetch/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[macro_use]
4extern crate serde_derive;
5
6pub mod downloader;
7mod helpers;
8pub mod source_resolver;
9
10#[cfg(feature = "std")]
11use regex::Regex;
12#[cfg(feature = "std")]
13use std::collections::HashMap;
14#[cfg(feature = "std")]
15use std::path::{Path, PathBuf};
16
17#[derive(Deserialize, Debug)]
18#[cfg(feature = "std")]
19pub struct CargoLockfile {
20    metadata: HashMap<String, String>,
21}
22
23impl CargoLockfile {
24    #[cfg(feature = "std")]
25    pub fn crates(&self) -> Vec<Crate> {
26        self.metadata
27            .iter()
28            .map(|(crate_part, checksum)| Crate::parse_from_parts(crate_part, checksum))
29            .collect()
30    }
31
32    #[cfg(feature = "std")]
33    pub fn fetchable_crates(&self) -> Vec<Crate> {
34        self.crates()
35            .into_iter()
36            .filter(|n| n.checksum.is_some())
37            .filter(|n| n.source == "registry+https://github.com/rust-lang/crates.io-index")
38            .collect()
39    }
40}
41
42#[derive(Debug, Clone)]
43pub struct Crate {
44    pub crate_name: String,
45    pub version: String,
46    pub source: String,
47    pub checksum: Option<String>,
48}
49
50impl Crate {
51    #[cfg(feature = "std")]
52    pub fn parse_from_parts(crate_part: &str, checksum: &str) -> Self {
53        let regex = Regex::new(r"(?m)checksum (.+) (.+) \((.+)\)").unwrap();
54        let caps = regex.captures(crate_part).unwrap();
55
56        let crate_name = caps.get(1).unwrap().as_str().to_owned();
57        let version = caps.get(2).unwrap().as_str().to_owned();
58        let source = caps.get(3).unwrap().as_str().to_owned();
59
60        let checksum = match checksum {
61            "<none>" => None,
62            other => Some(other.to_owned()),
63        };
64        Self {
65            crate_name,
66            version,
67            source,
68            checksum,
69        }
70    }
71}
72
73#[cfg(feature = "std")]
74pub trait CrateDownloadTarget {
75    fn crate_name(&self) -> &str;
76    fn version(&self) -> &str;
77    fn checksum(&self) -> &str;
78
79    fn target_path(&self) -> PathBuf;
80}
81
82#[cfg(feature = "std")]
83#[derive(Debug)]
84pub struct CargoCacheCrate<'a> {
85    _crate: &'a Crate,
86    cargo_dir: &'a Path,
87    registry_name: &'a str,
88}
89
90#[cfg(feature = "std")]
91impl<'a> CargoCacheCrate<'a> {
92    pub fn new(_crate: &'a Crate, cargo_dir: &'a Path, registry_name: &'a str) -> Self {
93        Self {
94            _crate,
95            cargo_dir,
96            registry_name,
97        }
98    }
99
100    pub fn cargo_crate(&self) -> &Crate {
101        &self._crate
102    }
103
104    /// Path to where the cache file of the crate should be stored.
105    pub fn cache_path(&self) -> PathBuf {
106        let mut path = self
107            .cargo_dir
108            .join("registry")
109            .join("cache")
110            .join(self.registry_name);
111        path = path.join(format!(
112            "{}-{}.crate",
113            self._crate.crate_name, self._crate.version
114        ));
115
116        path
117    }
118}
119
120#[cfg(feature = "std")]
121impl<'a> CrateDownloadTarget for CargoCacheCrate<'a> {
122    fn crate_name(&self) -> &str {
123        &self._crate.crate_name
124    }
125
126    fn version(&self) -> &str {
127        &self._crate.version
128    }
129
130    fn checksum(&self) -> &str {
131        self._crate.checksum.as_ref().unwrap()
132    }
133
134    fn target_path(&self) -> PathBuf {
135        self.cache_path()
136    }
137}