mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-21 04:58:42 +00:00
Refactor async_extracter
: Create multi extracters
dedicated to different tasks Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
bd68613448
commit
cbd57a1bce
2 changed files with 101 additions and 28 deletions
|
@ -1,18 +1,16 @@
|
||||||
use std::{
|
use std::path::{Path, PathBuf};
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use cargo_toml::Manifest;
|
use cargo_toml::Manifest;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use reqwest::Method;
|
use reqwest::{Method, Response};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tinytemplate::TinyTemplate;
|
use tinytemplate::TinyTemplate;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::{BinstallError, Meta, PkgFmt};
|
use crate::{BinstallError, Meta, PkgFmt, PkgFmtDecomposed};
|
||||||
|
|
||||||
mod async_extracter;
|
mod async_extracter;
|
||||||
pub use async_extracter::extract_archive_stream;
|
pub use async_extracter::*;
|
||||||
|
|
||||||
mod auto_abort_join_handle;
|
mod auto_abort_join_handle;
|
||||||
pub use auto_abort_join_handle::AutoAbortJoinHandle;
|
pub use auto_abort_join_handle::AutoAbortJoinHandle;
|
||||||
|
@ -45,13 +43,41 @@ pub async fn remote_exists(url: Url, method: Method) -> Result<bool, BinstallErr
|
||||||
Ok(req.status().is_success())
|
Ok(req.status().is_success())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn create_request(url: Url) -> Result<Response, BinstallError> {
|
||||||
|
reqwest::get(url.clone())
|
||||||
|
.await
|
||||||
|
.and_then(|r| r.error_for_status())
|
||||||
|
.map_err(|err| BinstallError::Http {
|
||||||
|
method: Method::GET,
|
||||||
|
url,
|
||||||
|
err,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Download a file from the provided URL and extract it to the provided path.
|
/// Download a file from the provided URL and extract it to the provided path.
|
||||||
pub async fn download_and_extract<P: AsRef<Path>>(
|
pub async fn download_and_extract<P: AsRef<Path>>(
|
||||||
url: Url,
|
url: Url,
|
||||||
fmt: PkgFmt,
|
fmt: PkgFmt,
|
||||||
path: P,
|
path: P,
|
||||||
) -> Result<(), BinstallError> {
|
) -> Result<(), BinstallError> {
|
||||||
download_and_extract_with_filter::<fn(&Path) -> bool, _>(url, fmt, path.as_ref(), None).await
|
debug!("Downloading from: '{url}'");
|
||||||
|
|
||||||
|
let resp = create_request(url).await?;
|
||||||
|
|
||||||
|
let path = path.as_ref();
|
||||||
|
debug!("Downloading to file: '{}'", path.display());
|
||||||
|
|
||||||
|
let stream = resp.bytes_stream();
|
||||||
|
|
||||||
|
match fmt.decompose() {
|
||||||
|
PkgFmtDecomposed::Tar(fmt) => extract_tar_based_stream(stream, path, fmt).await?,
|
||||||
|
PkgFmtDecomposed::Bin => extract_bin(stream, path).await?,
|
||||||
|
PkgFmtDecomposed::Zip => extract_zip(stream, path).await?,
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Download OK, written to file: '{}'", path.display());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Download a file from the provided URL and extract part of it to
|
/// Download a file from the provided URL and extract part of it to
|
||||||
|
@ -72,19 +98,20 @@ pub async fn download_and_extract_with_filter<
|
||||||
) -> Result<(), BinstallError> {
|
) -> Result<(), BinstallError> {
|
||||||
debug!("Downloading from: '{url}'");
|
debug!("Downloading from: '{url}'");
|
||||||
|
|
||||||
let resp = reqwest::get(url.clone())
|
let resp = create_request(url).await?;
|
||||||
.await
|
|
||||||
.and_then(|r| r.error_for_status())
|
|
||||||
.map_err(|err| BinstallError::Http {
|
|
||||||
method: Method::GET,
|
|
||||||
url,
|
|
||||||
err,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
debug!("Downloading to file: '{}'", path.display());
|
debug!("Downloading to file: '{}'", path.display());
|
||||||
|
|
||||||
extract_archive_stream(resp.bytes_stream(), path, fmt, filter).await?;
|
let stream = resp.bytes_stream();
|
||||||
|
|
||||||
|
match fmt.decompose() {
|
||||||
|
PkgFmtDecomposed::Tar(fmt) => {
|
||||||
|
extract_tar_based_stream_with_filter(stream, path, fmt, filter).await?
|
||||||
|
}
|
||||||
|
PkgFmtDecomposed::Bin => extract_bin(stream, path).await?,
|
||||||
|
PkgFmtDecomposed::Zip => extract_zip(stream, path).await?,
|
||||||
|
}
|
||||||
|
|
||||||
debug!("Download OK, written to file: '{}'", path.display());
|
debug!("Download OK, written to file: '{}'", path.display());
|
||||||
|
|
||||||
|
|
|
@ -199,24 +199,70 @@ impl AsyncExtracter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// * `output` - If `fmt` is `PkgFmt::Bin`, then this is the filename
|
pub async fn extract_bin<E>(
|
||||||
/// for the bin.
|
|
||||||
/// Otherwise, it is the directory where the extracted content will be put.
|
|
||||||
/// * `fmt` - The format of the archive to feed in.
|
|
||||||
/// * `filter` - If Some, then it will pass the path of the file to it
|
|
||||||
/// and only extract ones which filter returns `true`.
|
|
||||||
/// Note that this is a best-effort and it only works when `fmt`
|
|
||||||
/// is not `PkgFmt::Bin` or `PkgFmt::Zip`.
|
|
||||||
pub async fn extract_archive_stream<Filter: FnMut(&Path) -> bool + Send + 'static, E>(
|
|
||||||
mut stream: impl Stream<Item = Result<Bytes, E>> + Unpin,
|
mut stream: impl Stream<Item = Result<Bytes, E>> + Unpin,
|
||||||
output: &Path,
|
output: &Path,
|
||||||
fmt: PkgFmt,
|
|
||||||
filter: Option<Filter>,
|
|
||||||
) -> Result<(), BinstallError>
|
) -> Result<(), BinstallError>
|
||||||
where
|
where
|
||||||
BinstallError: From<E>,
|
BinstallError: From<E>,
|
||||||
{
|
{
|
||||||
let mut extracter = AsyncExtracter::new(output, fmt, filter);
|
let mut extracter = AsyncExtracter::new::<fn(&Path) -> bool>(output, PkgFmt::Bin, None);
|
||||||
|
|
||||||
|
while let Some(res) = stream.next().await {
|
||||||
|
extracter.feed(res?).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
extracter.done().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn extract_zip<E>(
|
||||||
|
mut stream: impl Stream<Item = Result<Bytes, E>> + Unpin,
|
||||||
|
output: &Path,
|
||||||
|
) -> Result<(), BinstallError>
|
||||||
|
where
|
||||||
|
BinstallError: From<E>,
|
||||||
|
{
|
||||||
|
let mut extracter = AsyncExtracter::new::<fn(&Path) -> bool>(output, PkgFmt::Zip, None);
|
||||||
|
|
||||||
|
while let Some(res) = stream.next().await {
|
||||||
|
extracter.feed(res?).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
extracter.done().await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// * `filter` - If Some, then it will pass the path of the file to it
|
||||||
|
/// and only extract ones which filter returns `true`.
|
||||||
|
pub async fn extract_tar_based_stream_with_filter<
|
||||||
|
Filter: FnMut(&Path) -> bool + Send + 'static,
|
||||||
|
E,
|
||||||
|
>(
|
||||||
|
mut stream: impl Stream<Item = Result<Bytes, E>> + Unpin,
|
||||||
|
output: &Path,
|
||||||
|
fmt: TarBasedFmt,
|
||||||
|
filter: Option<Filter>,
|
||||||
|
) -> Result<(), BinstallError>
|
||||||
|
where
|
||||||
|
BinstallError: From<E>,
|
||||||
|
{
|
||||||
|
let mut extracter = AsyncExtracter::new(output, fmt.into(), filter);
|
||||||
|
|
||||||
|
while let Some(res) = stream.next().await {
|
||||||
|
extracter.feed(res?).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
extracter.done().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn extract_tar_based_stream<E>(
|
||||||
|
mut stream: impl Stream<Item = Result<Bytes, E>> + Unpin,
|
||||||
|
output: &Path,
|
||||||
|
fmt: TarBasedFmt,
|
||||||
|
) -> Result<(), BinstallError>
|
||||||
|
where
|
||||||
|
BinstallError: From<E>,
|
||||||
|
{
|
||||||
|
let mut extracter = AsyncExtracter::new::<fn(&Path) -> bool>(output, fmt.into(), None);
|
||||||
|
|
||||||
while let Some(res) = stream.next().await {
|
while let Some(res) = stream.next().await {
|
||||||
extracter.feed(res?).await?;
|
extracter.feed(res?).await?;
|
||||||
|
|
Loading…
Add table
Reference in a new issue