1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::collections::HashMap;
use crate::{
error::{Error, ErrorKind},
package::{self, Package},
};
pub struct CachedIndex {
index: crates_index::Index,
cache: HashMap<package::Name, HashMap<String, bool>>,
}
impl CachedIndex {
pub fn fetch() -> Result<Self, Error> {
let mut index = crates_index::Index::new_cargo_default()?;
index.update()?;
Ok(CachedIndex {
index,
cache: Default::default(),
})
}
pub fn open() -> Result<Self, Error> {
let index = crates_index::Index::new_cargo_default()?;
Ok(CachedIndex {
index,
cache: Default::default(),
})
}
fn populate_cache(&mut self, package: &package::Name) -> Result<(), Error> {
let crate_releases = self.index.crate_(package.as_str()).ok_or_else(|| {
format_err!(
ErrorKind::NotFound,
"no such crate in the crates.io index: {}",
&package,
)
})?;
let versions: HashMap<String, bool> = crate_releases
.versions()
.iter()
.map(|v| (v.version().to_owned(), v.is_yanked()))
.collect();
self.cache.insert(package.to_owned(), versions);
Ok(())
}
pub fn is_yanked(&mut self, package: &Package) -> Result<bool, Error> {
let crate_is_cached = { self.cache.contains_key(&package.name) };
if !crate_is_cached {
self.populate_cache(&package.name)?
};
match &self.cache[&package.name].get(&package.version.to_string()) {
Some(is_yanked) => Ok(**is_yanked),
None => Err(format_err!(
ErrorKind::NotFound,
"No such version in crates.io index: {} {}",
&package.name,
&package.version
)),
}
}
pub fn find_yanked<'a, I>(&mut self, packages: I) -> Result<Vec<&'a Package>, Error>
where
I: IntoIterator<Item = &'a Package>,
{
let mut yanked = Vec::new();
for package in packages {
if self.is_yanked(package)? {
yanked.push(package);
}
}
Ok(yanked)
}
}