mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-06-15 15:16:37 +00:00
Add quickinstall support
This commit is contained in:
parent
b584038d0d
commit
4e0ca0c1c3
5 changed files with 75 additions and 18 deletions
|
@ -1,17 +1,17 @@
|
|||
use std::path::Path;
|
||||
|
||||
pub use gh_release::*;
|
||||
pub use quickinstall::*;
|
||||
|
||||
use crate::PkgMeta;
|
||||
|
||||
mod gh_release;
|
||||
mod quickinstall;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait Fetcher {
|
||||
/// Create a new fetcher from some data
|
||||
async fn new(data: &Data) -> Result<Self, anyhow::Error>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
async fn new(data: &Data) -> Result<Box<Self>, anyhow::Error> where Self: Sized;
|
||||
|
||||
/// Fetch a package
|
||||
async fn fetch(&self, dst: &Path) -> Result<(), anyhow::Error>;
|
||||
|
@ -21,10 +21,32 @@ pub trait Fetcher {
|
|||
}
|
||||
|
||||
/// Data required to fetch a package
|
||||
#[derive(Debug)]
|
||||
pub struct Data {
|
||||
pub name: String,
|
||||
pub target: String,
|
||||
pub version: String,
|
||||
pub repo: Option<String>,
|
||||
pub meta: PkgMeta,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MultiFetcher {
|
||||
fetchers: Vec<Box<dyn Fetcher>>,
|
||||
}
|
||||
|
||||
impl MultiFetcher {
|
||||
pub fn add(&mut self, fetcher: Box<dyn Fetcher>) {
|
||||
self.fetchers.push(fetcher);
|
||||
}
|
||||
|
||||
pub async fn first_available(&self) -> Option<&dyn Fetcher> {
|
||||
for fetcher in &self.fetchers {
|
||||
if fetcher.check().await.unwrap_or(false) {
|
||||
return Some(&**fetcher);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
use std::path::Path;
|
||||
|
||||
use log::{debug, info};
|
||||
use reqwest::Method;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{download, head, Template};
|
||||
use crate::{download, remote_exists, Template};
|
||||
use super::Data;
|
||||
|
||||
pub struct GhRelease {
|
||||
|
@ -12,7 +13,7 @@ pub struct GhRelease {
|
|||
|
||||
#[async_trait::async_trait]
|
||||
impl super::Fetcher for GhRelease {
|
||||
async fn new(data: &Data) -> Result<Self, anyhow::Error> {
|
||||
async fn new(data: &Data) -> Result<Box<Self>, anyhow::Error> {
|
||||
// Generate context for URL interpolation
|
||||
let ctx = Context {
|
||||
name: &data.name,
|
||||
|
@ -23,12 +24,12 @@ impl super::Fetcher for GhRelease {
|
|||
};
|
||||
debug!("Using context: {:?}", ctx);
|
||||
|
||||
Ok(Self { url: ctx.render(&data.meta.pkg_url)? })
|
||||
Ok(Box::new(Self { url: ctx.render(&data.meta.pkg_url)? }))
|
||||
}
|
||||
|
||||
async fn check(&self) -> Result<bool, anyhow::Error> {
|
||||
info!("Checking for package at: '{}'", self.url);
|
||||
head(&self.url).await
|
||||
remote_exists(&self.url, Method::OPTIONS).await
|
||||
}
|
||||
|
||||
async fn fetch(&self, dst: &Path) -> Result<(), anyhow::Error> {
|
||||
|
|
31
src/fetchers/quickinstall.rs
Normal file
31
src/fetchers/quickinstall.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use std::path::Path;
|
||||
|
||||
use log::info;
|
||||
use reqwest::Method;
|
||||
|
||||
use crate::{download, remote_exists};
|
||||
use super::Data;
|
||||
|
||||
pub struct QuickInstall {
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl super::Fetcher for QuickInstall {
|
||||
async fn new(data: &Data) -> Result<Box<Self>, anyhow::Error> {
|
||||
let crate_name = &data.name;
|
||||
let version = &data.version;
|
||||
let target = &data.target;
|
||||
Ok(Box::new(Self { url: format!("https://github.com/alsuren/cargo-quickinstall/releases/download/{crate_name}-{version}-{target}/{crate_name}-{version}-{target}.tar.gz") }))
|
||||
}
|
||||
|
||||
async fn check(&self) -> Result<bool, anyhow::Error> {
|
||||
info!("Checking for package at: '{}'", self.url);
|
||||
remote_exists(&self.url, Method::OPTIONS).await
|
||||
}
|
||||
|
||||
async fn fetch(&self, dst: &Path) -> Result<(), anyhow::Error> {
|
||||
info!("Downloading package from: '{}'", self.url);
|
||||
download(&self.url, dst).await
|
||||
}
|
||||
}
|
|
@ -26,8 +26,8 @@ pub fn load_manifest_path<P: AsRef<Path>>(manifest_path: P) -> Result<Manifest<M
|
|||
Ok(manifest)
|
||||
}
|
||||
|
||||
pub async fn head(url: &str) -> Result<bool, anyhow::Error> {
|
||||
let req = reqwest::Client::new().head(url).send().await?;
|
||||
pub async fn remote_exists(url: &str, method: reqwest::Method) -> Result<bool, anyhow::Error> {
|
||||
let req = reqwest::Client::new().request(method, url).send().await?;
|
||||
Ok(req.status().is_success())
|
||||
}
|
||||
|
||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -7,7 +7,7 @@ use structopt::StructOpt;
|
|||
|
||||
use tempdir::TempDir;
|
||||
|
||||
use cargo_binstall::{*, fetchers::{GhRelease, Data, Fetcher}, bins};
|
||||
use cargo_binstall::{*, fetchers::{GhRelease, Data, Fetcher, QuickInstall, MultiFetcher}, bins};
|
||||
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
|
@ -127,16 +127,19 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
repo: package.repository.clone(),
|
||||
meta: meta.clone(),
|
||||
};
|
||||
|
||||
// Try github releases
|
||||
let gh = GhRelease::new(&fetcher_data).await?;
|
||||
if !gh.check().await? {
|
||||
error!("No file found in github releases, cannot proceed");
|
||||
return Err(anyhow::anyhow!("No viable remote package found"));
|
||||
}
|
||||
|
||||
// Try github releases, then quickinstall
|
||||
let mut fetchers = MultiFetcher::default();
|
||||
fetchers.add(GhRelease::new(&fetcher_data).await?);
|
||||
fetchers.add(QuickInstall::new(&fetcher_data).await?);
|
||||
|
||||
let fetcher = fetchers.first_available().await.ok_or_else(|| {
|
||||
error!("File does not exist remotely, cannot proceed");
|
||||
anyhow::anyhow!("No viable remote package found")
|
||||
})?;
|
||||
|
||||
// Download package
|
||||
gh.fetch(&pkg_path).await?;
|
||||
fetcher.fetch(&pkg_path).await?;
|
||||
|
||||
#[cfg(incomplete)]
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue