Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: realease toolkit-cli 0.0.1 #95

Merged
merged 5 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
61 changes: 1 addition & 60 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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"
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <your-manifest-path>
```

### Using a release binary

1. Download the [latest release](https://github.com/apptools-lab/AppToolkit/releases) binary for your system
Expand Down
48 changes: 35 additions & 13 deletions src/utils/download_file.rs
Original file line number Diff line number Diff line change
@@ -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<PathBuf> {
Expand Down Expand Up @@ -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<String> {
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<String> {
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<String> {
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(())
}
}
6 changes: 2 additions & 4 deletions src/utils/extract_zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ pub fn extract_zip<T: AsRef<Path>>(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]
Expand Down
Loading