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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::time::Duration;
use std::path::{Path, PathBuf};
use log::{debug};
use anyhow::{Context, anyhow};
use semver::{Version, VersionReq};
use crates_io_api::AsyncClient;
use crate::PkgFmt;
use crate::helpers::*;
fn find_version<'a, V: Iterator<Item=&'a str>>(requirement: &str, version_iter: V) -> Result<String, anyhow::Error> {
let version_req = VersionReq::parse(requirement)?;
let mut filtered: Vec<_> = version_iter.filter(|v| {
let ver_str = match v.strip_prefix("s") {
Some(v) => v,
None => v,
};
let ver = match Version::parse(ver_str) {
Ok(sv) => sv,
Err(_) => return false,
};
debug!("Version: {:?}", ver);
version_req.matches(&ver)
}).collect();
filtered.sort_by(|a, b| {
let a = Version::parse(a).unwrap();
let b = Version::parse(b).unwrap();
b.partial_cmp(&a).unwrap()
});
debug!("Filtered: {:?}", filtered);
match filtered.get(0) {
Some(v) => Ok(v.to_string()),
None => Err(anyhow!("No matching version for requirement: '{}'", version_req))
}
}
pub async fn fetch_crate_cratesio(name: &str, version_req: &str, temp_dir: &Path) -> Result<PathBuf, anyhow::Error> {
debug!("Updating crates.io index");
let index = crates_index::Index::new_cargo_default();
index.retrieve_or_update()?;
debug!("Looking up crate information");
let base_info = match index.crate_(name) {
Some(i) => i,
None => {
return Err(anyhow::anyhow!("Error fetching information for crate {}", name));
}
};
let version_iter = base_info.versions().iter().map(|v| v.version() );
let version_name = find_version(version_req, version_iter)?;
let api_client = AsyncClient::new("cargo-binstall (https://github.com/ryankurte/cargo-binstall)", Duration::from_millis(100))?;
let crate_info = api_client.get_crate(name.as_ref()).await
.context("Error fetching crate information")?;
let version = match crate_info.versions.iter().find(|v| v.num == version_name) {
Some(v) => v,
None => {
return Err(anyhow::anyhow!("No information found for crate: '{}' version: '{}'",
name, version_name));
}
};
debug!("Found information for crate version: '{}'", version.num);
let crate_url = format!("https://crates.io/{}", version.dl_path);
let tgz_path = temp_dir.join(format!("{}.tgz", name));
debug!("Fetching crate from: {}", crate_url);
download(&crate_url, &tgz_path).await?;
debug!("Decompressing crate archive");
extract(&tgz_path, PkgFmt::Tgz, &temp_dir)?;
let crate_path = temp_dir.join(format!("{}-{}", name, version_name));
Ok(crate_path)
}
pub async fn fetch_crate_gh_releases(_name: &str, _version: Option<&str>, _temp_dir: &Path) -> Result<PathBuf, anyhow::Error> {
unimplemented!();
}