mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-24 14:28:42 +00:00
Optimize fetch_crate_cratesio
for exact version (#1089)
If `version_req` requests a specific version instead of a range, then there is no need to pull all versions available from https://crates.io/api/v1/crates Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
256fb36e74
commit
e96477a116
1 changed files with 102 additions and 30 deletions
|
@ -1,8 +1,8 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use cargo_toml::Manifest;
|
||||
use compact_str::CompactString;
|
||||
use semver::VersionReq;
|
||||
use compact_str::{CompactString, ToCompactString};
|
||||
use semver::{Comparator, Op as ComparatorOp, Version as SemVersion, VersionReq};
|
||||
use serde::Deserialize;
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -21,38 +21,68 @@ mod vfs;
|
|||
mod visitor;
|
||||
use visitor::ManifestVisitor;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CrateInfo {
|
||||
#[serde(rename = "crate")]
|
||||
inner: CrateInfoInner,
|
||||
async fn is_crate_yanked(
|
||||
client: &Client,
|
||||
name: &str,
|
||||
version: &str,
|
||||
) -> Result<bool, BinstallError> {
|
||||
#[derive(Deserialize)]
|
||||
struct CrateInfo {
|
||||
version: Inner,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Inner {
|
||||
yanked: bool,
|
||||
}
|
||||
|
||||
// Fetch / update index
|
||||
debug!("Looking up crate information");
|
||||
|
||||
let response = client
|
||||
.get(Url::parse(&format!(
|
||||
"https://crates.io/api/v1/crates/{name}/{version}"
|
||||
))?)
|
||||
.send(true)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
BinstallError::CratesIoApi(Box::new(CratesIoApiError {
|
||||
crate_name: name.into(),
|
||||
err,
|
||||
}))
|
||||
})?;
|
||||
|
||||
let info: CrateInfo = response.json().await?;
|
||||
|
||||
Ok(info.version.yanked)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CrateInfoInner {
|
||||
max_stable_version: CompactString,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Versions {
|
||||
versions: Vec<Version>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Version {
|
||||
num: CompactString,
|
||||
yanked: bool,
|
||||
}
|
||||
|
||||
/// Find the crate by name, get its latest stable version matches `version_req`,
|
||||
/// retrieve its Cargo.toml and infer all its bins.
|
||||
pub async fn fetch_crate_cratesio(
|
||||
client: Client,
|
||||
async fn fetch_crate_cratesio_version_matched(
|
||||
client: &Client,
|
||||
name: &str,
|
||||
version_req: &VersionReq,
|
||||
crates_io_rate_limit: &CratesIoRateLimit,
|
||||
) -> Result<Manifest<Meta>, BinstallError> {
|
||||
// Wait until we can make another request to crates.io
|
||||
crates_io_rate_limit.tick().await;
|
||||
) -> Result<CompactString, BinstallError> {
|
||||
#[derive(Deserialize)]
|
||||
struct CrateInfo {
|
||||
#[serde(rename = "crate")]
|
||||
inner: CrateInfoInner,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CrateInfoInner {
|
||||
max_stable_version: CompactString,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Versions {
|
||||
versions: Vec<Version>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Version {
|
||||
num: CompactString,
|
||||
yanked: bool,
|
||||
}
|
||||
|
||||
// Fetch / update index
|
||||
debug!("Looking up crate information");
|
||||
|
@ -106,6 +136,48 @@ pub async fn fetch_crate_cratesio(
|
|||
|
||||
debug!("Found information for crate version: '{version}'");
|
||||
|
||||
Ok(version)
|
||||
}
|
||||
|
||||
/// Find the crate by name, get its latest stable version matches `version_req`,
|
||||
/// retrieve its Cargo.toml and infer all its bins.
|
||||
pub async fn fetch_crate_cratesio(
|
||||
client: Client,
|
||||
name: &str,
|
||||
version_req: &VersionReq,
|
||||
crates_io_rate_limit: &CratesIoRateLimit,
|
||||
) -> Result<Manifest<Meta>, BinstallError> {
|
||||
// Wait until we can make another request to crates.io
|
||||
crates_io_rate_limit.tick().await;
|
||||
|
||||
let version = match version_req.comparators.as_slice() {
|
||||
[Comparator {
|
||||
op: ComparatorOp::Exact,
|
||||
major,
|
||||
minor: Some(minor),
|
||||
patch: Some(patch),
|
||||
pre,
|
||||
}] => {
|
||||
let version = SemVersion {
|
||||
major: *major,
|
||||
minor: *minor,
|
||||
patch: *patch,
|
||||
pre: pre.clone(),
|
||||
build: Default::default(),
|
||||
}
|
||||
.to_compact_string();
|
||||
|
||||
if is_crate_yanked(&client, name, &version).await? {
|
||||
return Err(BinstallError::VersionMismatch {
|
||||
req: version_req.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
_ => fetch_crate_cratesio_version_matched(&client, name, version_req).await?,
|
||||
};
|
||||
|
||||
// Download crate to temporary dir (crates.io or git?)
|
||||
let crate_url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue