mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-05-05 11:40:04 +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
|
@ -1,20 +1,23 @@
|
|||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use log::{debug, info, error};
|
||||
use log::{debug, error, info};
|
||||
|
||||
use cargo_toml::{Manifest};
|
||||
use cargo_toml::Manifest;
|
||||
use flate2::read::GzDecoder;
|
||||
use serde::Serialize;
|
||||
use tar::Archive;
|
||||
use tinytemplate::TinyTemplate;
|
||||
use xz2::read::XzDecoder;
|
||||
use zip::read::ZipArchive;
|
||||
|
||||
use crate::{Meta};
|
||||
use crate::Meta;
|
||||
|
||||
use super::PkgFmt;
|
||||
|
||||
/// Load binstall metadata from the crate `Cargo.toml` at the provided path
|
||||
pub fn load_manifest_path<P: AsRef<Path>>(manifest_path: P) -> Result<Manifest<Meta>, anyhow::Error> {
|
||||
pub fn load_manifest_path<P: AsRef<Path>>(
|
||||
manifest_path: P,
|
||||
) -> Result<Manifest<Meta>, anyhow::Error> {
|
||||
debug!("Reading manifest: {}", manifest_path.as_ref().display());
|
||||
|
||||
// Load and parse manifest (this checks file system for binary output names)
|
||||
|
@ -24,9 +27,13 @@ pub fn load_manifest_path<P: AsRef<Path>>(manifest_path: P) -> Result<Manifest<M
|
|||
Ok(manifest)
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
/// Download a file from the provided URL to the provided path
|
||||
pub async fn download<P: AsRef<Path>>(url: &str, path: P) -> Result<(), anyhow::Error> {
|
||||
|
||||
debug!("Downloading from: '{}'", url);
|
||||
|
||||
let resp = reqwest::get(url).await?;
|
||||
|
@ -46,51 +53,75 @@ pub async fn download<P: AsRef<Path>>(url: &str, path: P) -> Result<(), anyhow::
|
|||
}
|
||||
|
||||
/// Extract files from the specified source onto the specified path
|
||||
pub fn extract<S: AsRef<Path>, P: AsRef<Path>>(source: S, fmt: PkgFmt, path: P) -> Result<(), anyhow::Error> {
|
||||
pub fn extract<S: AsRef<Path>, P: AsRef<Path>>(
|
||||
source: S,
|
||||
fmt: PkgFmt,
|
||||
path: P,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
match fmt {
|
||||
PkgFmt::Tar => {
|
||||
// Extract to install dir
|
||||
debug!("Extracting from tar archive '{:?}' to `{:?}`", source.as_ref(), path.as_ref());
|
||||
debug!(
|
||||
"Extracting from tar archive '{:?}' to `{:?}`",
|
||||
source.as_ref(),
|
||||
path.as_ref()
|
||||
);
|
||||
|
||||
let dat = std::fs::File::open(source)?;
|
||||
let mut tar = Archive::new(dat);
|
||||
|
||||
tar.unpack(path)?;
|
||||
},
|
||||
}
|
||||
PkgFmt::Tgz => {
|
||||
// Extract to install dir
|
||||
debug!("Decompressing from tgz archive '{:?}' to `{:?}`", source.as_ref(), path.as_ref());
|
||||
debug!(
|
||||
"Decompressing from tgz archive '{:?}' to `{:?}`",
|
||||
source.as_ref(),
|
||||
path.as_ref()
|
||||
);
|
||||
|
||||
let dat = std::fs::File::open(source)?;
|
||||
let tar = GzDecoder::new(dat);
|
||||
let mut tgz = Archive::new(tar);
|
||||
|
||||
tgz.unpack(path)?;
|
||||
},
|
||||
}
|
||||
PkgFmt::Txz => {
|
||||
// Extract to install dir
|
||||
debug!("Decompressing from txz archive '{:?}' to `{:?}`", source.as_ref(), path.as_ref());
|
||||
debug!(
|
||||
"Decompressing from txz archive '{:?}' to `{:?}`",
|
||||
source.as_ref(),
|
||||
path.as_ref()
|
||||
);
|
||||
|
||||
let dat = std::fs::File::open(source)?;
|
||||
let tar = XzDecoder::new(dat);
|
||||
let mut txz = Archive::new(tar);
|
||||
|
||||
txz.unpack(path)?;
|
||||
},
|
||||
}
|
||||
PkgFmt::Zip => {
|
||||
// Extract to install dir
|
||||
debug!("Decompressing from zip archive '{:?}' to `{:?}`", source.as_ref(), path.as_ref());
|
||||
debug!(
|
||||
"Decompressing from zip archive '{:?}' to `{:?}`",
|
||||
source.as_ref(),
|
||||
path.as_ref()
|
||||
);
|
||||
|
||||
let dat = std::fs::File::open(source)?;
|
||||
let mut zip = ZipArchive::new(dat)?;
|
||||
|
||||
zip.extract(path)?;
|
||||
},
|
||||
}
|
||||
PkgFmt::Bin => {
|
||||
debug!("Copying binary '{:?}' to `{:?}`", source.as_ref(), path.as_ref());
|
||||
debug!(
|
||||
"Copying binary '{:?}' to `{:?}`",
|
||||
source.as_ref(),
|
||||
path.as_ref()
|
||||
);
|
||||
// Copy to install dir
|
||||
std::fs::copy(source, path)?;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
@ -101,7 +132,7 @@ pub fn extract<S: AsRef<Path>, P: AsRef<Path>>(source: S, fmt: PkgFmt, path: P)
|
|||
pub fn get_install_path<P: AsRef<Path>>(install_path: Option<P>) -> Option<PathBuf> {
|
||||
// Command line override first first
|
||||
if let Some(p) = install_path {
|
||||
return Some(PathBuf::from(p.as_ref()))
|
||||
return Some(PathBuf::from(p.as_ref()));
|
||||
}
|
||||
|
||||
// Environmental variables
|
||||
|
@ -144,8 +175,24 @@ pub fn confirm() -> Result<bool, anyhow::Error> {
|
|||
match input.as_str().trim() {
|
||||
"yes" => Ok(true),
|
||||
"no" => Ok(false),
|
||||
_ => {
|
||||
Err(anyhow::anyhow!("Valid options are 'yes', 'no', please try again"))
|
||||
}
|
||||
_ => Err(anyhow::anyhow!(
|
||||
"Valid options are 'yes', 'no', please try again"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Template: Serialize {
|
||||
fn render(&self, template: &str) -> Result<String, anyhow::Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// Create template instance
|
||||
let mut tt = TinyTemplate::new();
|
||||
|
||||
// Add template to instance
|
||||
tt.add_template("path", &template)?;
|
||||
|
||||
// Render output
|
||||
Ok(tt.render("path", self)?)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue