diff --git a/CHANGELOG.md b/CHANGELOG.md index b92656a..4411922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 0.0.1 + +- chore: reduce the size of the release binary +- feat: support download the file with content-type `application/x-msdownload` + ## 0.0.0 - Initial Release diff --git a/Cargo.lock b/Cargo.lock index abbcf85..c7c889f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -603,16 +603,6 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.21" @@ -744,29 +734,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "parking_lot" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.5", -] - [[package]] name = "path-absolutize" version = "3.1.1" @@ -853,15 +820,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.5.0", -] - [[package]] name = "regex" version = "1.10.4" @@ -994,12 +952,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "security-framework" version = "2.10.0" @@ -1066,15 +1018,6 @@ dependencies = [ "serde", ] -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "slab" version = "0.4.9" @@ -1182,9 +1125,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.48.0", @@ -1226,7 +1167,7 @@ dependencies = [ [[package]] name = "toolkit" -version = "0.0.0" +version = "0.0.1" dependencies = [ "anyhow", "backtrace", diff --git a/Cargo.toml b/Cargo.toml index 0d5b932..26f6a26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "toolkit" -version = "0.0.0" +version = "0.0.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -20,7 +20,7 @@ regex = "1.10.4" reqwest = { version = "0.12.4", features = ["json", "stream"] } serde = { version = "1.0.200", features = ["derive"] } serde_json = "1.0.116" -tokio = { version = "1.37.0", features = ["full"] } +tokio = { version = "1.37.0", features = ["rt", "rt-multi-thread", "macros", "fs"] } walkdir = "2.5.0" [target.'cfg(windows)'.dependencies] winreg = "0.52.0" diff --git a/README.md b/README.md index ddc225f..4088aa9 100644 --- a/README.md +++ b/README.md @@ -31,16 +31,12 @@ Install the recommended toolkits (for web development) Install your toolkits by specifying the manifest file path. For example: ```shell +# install the recommended toolkits (for web development) +curl -fsSL https://raw.githubusercontent.com/apptools-lab/AppToolkit/feat/cli/shell/install.sh | bash -s -- --install +# install your toolkits by specifying the manifest file path curl -fsSL https://raw.githubusercontent.com/apptools-lab/AppToolkit/feat/cli/shell/install.sh | bash -s -- --install --manifest https://the-remote-server/your-toolkits-manifest-path ``` -```shell -# install the recommended toolkits(for web development) -$ .\toolkit.exe install -# install your custom toolkits by specifying the manifest file path -$ .\toolkit.exe install --manifest -``` - ### Using a release binary 1. Download the [latest release](https://github.com/apptools-lab/AppToolkit/releases) binary for your system diff --git a/src/utils/download_file.rs b/src/utils/download_file.rs index b0ae028..f20a934 100644 --- a/src/utils/download_file.rs +++ b/src/utils/download_file.rs @@ -1,7 +1,7 @@ use anyhow::Result; use futures_util::StreamExt; use regex::Regex; -use reqwest::{Client, Response, Url}; +use reqwest::{header::HeaderValue, Client, Response, Url}; use std::{cmp::min, env, fs::File, io::Write, path::PathBuf}; pub async fn download_file(url: &str, set_process_message: impl Fn(&str)) -> Result { @@ -44,33 +44,55 @@ pub async fn download_file(url: &str, set_process_message: impl Fn(&str)) -> Res } fn get_file_name_from_response(response: &Response) -> Result { - let content_disposition = response - .headers() - .get("content-disposition") - .ok_or(anyhow::anyhow!("Failed to get content-disposition header"))? + let headers = response.headers(); + let url = response.url().as_str(); + + if let Some(content_disposition) = headers.get("content-disposition") { + get_file_name_by_content_disposition(content_disposition, url) + } else { + get_last_segment_from_url(url) + } +} + +fn get_last_segment_from_url(url: &str) -> Result { + let url = Url::parse(url).map_err(|err| anyhow::anyhow!("Failed to parse url '{}'. Error: {}", url, err))?; + Ok(url.path_segments().unwrap().last().unwrap().to_string()) +} + +fn get_file_name_by_content_disposition(content_disposition: &HeaderValue, url: &str) -> Result { + let content_disposition = content_disposition .to_str() .map_err(|err| anyhow::anyhow!("Failed to convert content-disposition header to string. Error: {}", err))?; if content_disposition == "attachment" { - let url = response.url(); - let filename = Url::parse(response.url().as_str()) - .map_err(|err| anyhow::anyhow!("Failed to parse url '{}'. Error: {}", url, err)) - .map(|url| url.path_segments().unwrap().last().unwrap().to_string())?; - Ok(filename) + get_last_segment_from_url(url) } else { let re = Regex::new(r"filename=([^;]+)").map_err(|err| anyhow::anyhow!("Failed to create regex. Error: {}", err))?; let file_name = re .captures(content_disposition) .ok_or(anyhow::anyhow!( - "Failed to get file name from content-disposition header" + "failed to match filename field from content-disposition header" ))? .get(1) .ok_or(anyhow::anyhow!( - "Failed to get file name from content-disposition header" + "failed to get filename field from content-disposition header" ))? .as_str() .replace('"', ""); - Ok(file_name) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_download_file() -> Result<()> { + // Windows exe file + let download_result = download_file("https://releases.arc.net/windows/ArcInstaller.exe", |_| {}).await?; + assert!(download_result.exists()); + + Ok(()) + } +} diff --git a/src/utils/extract_zip.rs b/src/utils/extract_zip.rs index 802ce3c..a79c3d9 100644 --- a/src/utils/extract_zip.rs +++ b/src/utils/extract_zip.rs @@ -10,11 +10,9 @@ pub fn extract_zip>(zip_path: T, extract_path: &str) -> Result<() #[cfg(test)] mod tests { - use std::fs; - - use crate::download_file; - pub use super::*; + use crate::download_file; + use std::fs; #[cfg(target_os = "macos")] #[tokio::test]