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 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}