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:
Félix Saparelli 2022-02-16 14:49:07 +13:00 committed by GitHub
parent e691255650
commit 370ae05620
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 600 additions and 209 deletions

View file

@ -1,10 +1,7 @@
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use strum_macros::{Display, EnumString, EnumVariantNames};
use tinytemplate::TinyTemplate;
pub mod helpers;
pub use helpers::*;
@ -12,20 +9,23 @@ pub use helpers::*;
pub mod drivers;
pub use drivers::*;
pub mod bins;
pub mod fetchers;
/// Compiled target triple, used as default for binary fetching
pub const TARGET: &'static str = env!("TARGET");
/// Default package path template (may be overridden in package Cargo.toml)
pub const DEFAULT_PKG_URL: &'static str = "{ repo }/releases/download/v{ version }/{ name }-{ target }-v{ version }.{ format }";
pub const DEFAULT_PKG_URL: &'static str =
"{ repo }/releases/download/v{ version }/{ name }-{ target }-v{ version }.{ format }";
/// Default binary name template (may be overridden in package Cargo.toml)
pub const DEFAULT_BIN_PATH: &'static str = "{ name }-{ target }-v{ version }/{ bin }{ format }";
/// Binary format enumeration
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Display, EnumString, EnumVariantNames)]
#[derive(
Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Display, EnumString, EnumVariantNames,
)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum PkgFmt {
@ -131,7 +131,6 @@ impl Default for PkgOverride {
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct BinMeta {
@ -141,36 +140,9 @@ pub struct BinMeta {
pub path: String,
}
/// Template for constructing download paths
#[derive(Clone, Debug, Serialize)]
pub struct Context {
pub name: String,
pub repo: Option<String>,
pub target: String,
pub version: String,
pub format: String,
pub bin: Option<String>,
}
impl Context {
/// Render the context into the provided template
pub fn render(&self, template: &str) -> Result<String, anyhow::Error> {
// Create template instance
let mut tt = TinyTemplate::new();
// Add template to instance
tt.add_template("path", &template)?;
// Render output
let rendered = tt.render("path", self)?;
Ok(rendered)
}
}
#[cfg(test)]
mod test {
use crate::{load_manifest_path};
use crate::load_manifest_path;
use cargo_toml::Product;
@ -187,7 +159,7 @@ mod test {
let manifest = load_manifest_path(&manifest_dir).expect("Error parsing metadata");
let package = manifest.package.unwrap();
let meta = package.metadata.map(|m| m.binstall ).flatten().unwrap();
let meta = package.metadata.map(|m| m.binstall).flatten().unwrap();
assert_eq!(&package.name, "cargo-binstall");
@ -198,14 +170,12 @@ mod test {
assert_eq!(
manifest.bin.as_slice(),
&[
Product{
name: Some("cargo-binstall".to_string()),
path: Some("src/main.rs".to_string()),
edition: Some(cargo_toml::Edition::E2018),
..Default::default()
},
],
&[Product {
name: Some("cargo-binstall".to_string()),
path: Some("src/main.rs".to_string()),
edition: Some(cargo_toml::Edition::E2018),
..Default::default()
},],
);
}
}