mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-05-06 04:00:02 +00:00
QuickInstall support (#94)
See this issue: https://github.com/alsuren/cargo-quickinstall/issues/27 Quick Install is a hosted repo of built crates, essentially. The approach I've taken here is a list of strategies: 1. First, we check the crate meta or default and build the URL to the repo. Once we have that, we perform a `HEAD` request to the URL to see if it's available. 2. If it's not, we build the URL to the quickinstall repo, and perform a `HEAD` to there. As soon as we've got a hit, we use that. I've built it so it's extensible with more strategies. This could be useful for #4. This also adds a prompt before downloading from third-party sources, and logs a short name for a source, which is easier to glance than a full URL, and includes a quick refactor of the install/link machinery.
This commit is contained in:
parent
e691255650
commit
370ae05620
12 changed files with 600 additions and 209 deletions
74
src/fetchers/gh_crate_meta.rs
Normal file
74
src/fetchers/gh_crate_meta.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use std::path::Path;
|
||||
|
||||
use log::{debug, info};
|
||||
use reqwest::Method;
|
||||
use serde::Serialize;
|
||||
use url::Url;
|
||||
|
||||
use super::Data;
|
||||
use crate::{download, remote_exists, PkgFmt, Template};
|
||||
|
||||
pub struct GhCrateMeta {
|
||||
url: Url,
|
||||
pkg_fmt: PkgFmt,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl super::Fetcher for GhCrateMeta {
|
||||
async fn new(data: &Data) -> Result<Box<Self>, anyhow::Error> {
|
||||
// Generate context for URL interpolation
|
||||
let ctx = Context {
|
||||
name: &data.name,
|
||||
repo: data.repo.as_ref().map(|s| &s[..]),
|
||||
target: &data.target,
|
||||
version: &data.version,
|
||||
format: data.meta.pkg_fmt.to_string(),
|
||||
};
|
||||
debug!("Using context: {:?}", ctx);
|
||||
|
||||
Ok(Box::new(Self {
|
||||
url: Url::parse(&ctx.render(&data.meta.pkg_url)?)?,
|
||||
pkg_fmt: data.meta.pkg_fmt,
|
||||
}))
|
||||
}
|
||||
|
||||
async fn check(&self) -> Result<bool, anyhow::Error> {
|
||||
info!("Checking for package at: '{}'", self.url);
|
||||
remote_exists(self.url.as_str(), Method::HEAD).await
|
||||
}
|
||||
|
||||
async fn fetch(&self, dst: &Path) -> Result<(), anyhow::Error> {
|
||||
info!("Downloading package from: '{}'", self.url);
|
||||
download(self.url.as_str(), dst).await
|
||||
}
|
||||
|
||||
fn pkg_fmt(&self) -> PkgFmt {
|
||||
self.pkg_fmt
|
||||
}
|
||||
|
||||
fn source_name(&self) -> String {
|
||||
if let Some(domain) = self.url.domain() {
|
||||
domain.to_string()
|
||||
} else if let Some(host) = self.url.host_str() {
|
||||
host.to_string()
|
||||
} else {
|
||||
self.url.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_third_party(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Template for constructing download paths
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
struct Context<'c> {
|
||||
pub name: &'c str,
|
||||
pub repo: Option<&'c str>,
|
||||
pub target: &'c str,
|
||||
pub version: &'c str,
|
||||
pub format: String,
|
||||
}
|
||||
|
||||
impl<'c> Template for Context<'c> {}
|
Loading…
Add table
Add a link
Reference in a new issue