Skip to content

Commit

Permalink
Optimize fetch_crate_cratesio for exact version
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
NobodyXu committed May 25, 2023
1 parent 8e04ee1 commit 6fb8919
Showing 1 changed file with 99 additions and 27 deletions.
126 changes: 99 additions & 27 deletions crates/binstalk/src/drivers/crates_io.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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,
}

#[derive(Deserialize)]
struct CrateInfoInner {
max_stable_version: CompactString,
}
// Fetch / update index
debug!("Looking up crate information");

#[derive(Deserialize)]
struct Versions {
versions: Vec<Version>,
}
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?;

#[derive(Deserialize)]
struct Version {
num: CompactString,
yanked: bool,
Ok(info.version.yanked)
}

/// 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");
Expand Down Expand Up @@ -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");

Expand Down

0 comments on commit 6fb8919

Please sign in to comment.