mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-06-16 07:36:38 +00:00
131 lines
3.7 KiB
Rust
131 lines
3.7 KiB
Rust
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use log::{debug, info, error};
|
|
|
|
use cargo_toml::{Manifest};
|
|
use flate2::read::GzDecoder;
|
|
use tar::Archive;
|
|
|
|
|
|
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> {
|
|
debug!("Reading manifest: {}", manifest_path.as_ref().display());
|
|
|
|
// Load and parse manifest (this checks file system for binary output names)
|
|
let manifest = Manifest::<Meta>::from_path_with_metadata(manifest_path)?;
|
|
|
|
// Return metadata
|
|
Ok(manifest)
|
|
}
|
|
|
|
/// 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?;
|
|
|
|
if !resp.status().is_success() {
|
|
error!("Download error: {}", resp.status());
|
|
return Err(anyhow::anyhow!(resp.status()));
|
|
}
|
|
|
|
let bytes = resp.bytes().await?;
|
|
|
|
debug!("Download OK, writing to file: '{:?}'", path.as_ref());
|
|
|
|
std::fs::write(&path, bytes)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// 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> {
|
|
match fmt {
|
|
PkgFmt::Tar => {
|
|
// Extract to install dir
|
|
debug!("Extracting from 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 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::Bin => {
|
|
debug!("Copying data from archive '{:?}' to `{:?}`", source.as_ref(), path.as_ref());
|
|
// Copy to install dir
|
|
std::fs::copy(source, path)?;
|
|
},
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Fetch install path from environment
|
|
/// roughly follows https://doc.rust-lang.org/cargo/commands/cargo-install.html#description
|
|
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()))
|
|
}
|
|
|
|
// Environmental variables
|
|
if let Ok(p) = std::env::var("CARGO_INSTALL_ROOT") {
|
|
debug!("using CARGO_INSTALL_ROOT ({})", p);
|
|
let b = PathBuf::from(p);
|
|
return Some(b.join("bin"));
|
|
}
|
|
if let Ok(p) = std::env::var("CARGO_HOME") {
|
|
debug!("using CARGO_HOME ({})", p);
|
|
let b = PathBuf::from(p);
|
|
return Some(b.join("bin"));
|
|
}
|
|
|
|
// Standard $HOME/.cargo/bin
|
|
if let Some(d) = dirs::home_dir() {
|
|
let d = d.join(".cargo/bin");
|
|
if d.exists() {
|
|
debug!("using $HOME/.cargo/bin");
|
|
|
|
return Some(d);
|
|
}
|
|
}
|
|
|
|
// Local executable dir if no cargo is found
|
|
if let Some(d) = dirs::executable_dir() {
|
|
debug!("Fallback to {}", d.display());
|
|
return Some(d.into());
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
pub fn confirm() -> Result<bool, anyhow::Error> {
|
|
info!("Do you wish to continue? yes/no");
|
|
|
|
let mut input = String::new();
|
|
std::io::stdin().read_line(&mut input)?;
|
|
|
|
match input.as_str().trim() {
|
|
"yes" => Ok(true),
|
|
"no" => Ok(false),
|
|
_ => {
|
|
Err(anyhow::anyhow!("Valid options are 'yes', 'no', please try again"))
|
|
}
|
|
}
|
|
}
|