Skip to content
This repository was archived by the owner on Jan 21, 2026. It is now read-only.

Commit f5c96b0

Browse files
committed
allow specifying extract directory; fix extract when output is not specified
1 parent 00d2b5d commit f5c96b0

6 files changed

Lines changed: 44 additions & 6 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ soar-dl --github "pkgforge/soar" --gitlab "18817634" --output "final/"
4545
soar-dl --github "pkgforge/soar" --gitlab "18817634" --output "final"
4646

4747
# Extract archives automatically (only `tar.gz`, `tar.xz`, `tar.zstd`, `tar.bz2`, and `zip` are supported)
48-
soar-dl "https://github.com/pkgforge/soar/releases/download/v0.5.14/soar-x86_64-linux.tar.gz" --extract
48+
soar-dl "https://github.com/pkgforge/soar/releases/download/v0.5.14/soar-x86_64-linux.tar.gz" --extract --extract-dir extracted
4949

5050
# Stream response to stdout
5151
# If you like to pipe the response to other commands, also use quiet mode `-q` to silence other outputs
52-
soar-dl "https://github.com/pkgforge/soar/releases/download/v0.5.14/soar-x86_64-linux.tar.gz" -O-
52+
soar-dl "https://github.com/pkgforge/soar/releases/download/v0.5.14/soar-x86_64-linux.tar.gz" -o-
5353
```
5454

5555
## Command Line Options

src/bin/soar-dl/cli.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ pub struct Args {
6565
#[arg(required = false, long)]
6666
pub extract: bool,
6767

68+
/// Directory where to extract the archive
69+
#[arg(required = false, long)]
70+
pub extract_dir: Option<String>,
71+
6872
/// Quiet mode
6973
#[arg(required = false, long, short)]
7074
pub quiet: bool,

src/bin/soar-dl/download_manager.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ impl DownloadManager {
6363
exclude_keywords: self.args.exclude_keywords.clone().unwrap_or_default(),
6464
exact_case: false,
6565
extract_archive: self.args.extract,
66+
extract_dir: self.args.extract_dir.clone(),
6667
}
6768
}
6869

@@ -192,6 +193,7 @@ impl DownloadManager {
192193
output_path: self.args.output.clone(),
193194
progress_callback: Some(self.progress_callback.clone()),
194195
extract_archive: self.args.extract,
196+
extract_dir: self.args.extract_dir.clone(),
195197
};
196198
let _ = downloader
197199
.download(options)

src/downloader.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ use crate::{
2222
archive,
2323
error::DownloadError,
2424
oci::{OciClient, OciLayer, OciManifest, Reference},
25-
utils::{extract_filename, extract_filename_from_url, is_elf, matches_pattern},
25+
utils::{
26+
build_absolute_path, extract_filename, extract_filename_from_url, is_elf, matches_pattern,
27+
},
2628
};
2729

2830
#[derive(Debug, Clone)]
@@ -40,6 +42,7 @@ pub struct DownloadOptions {
4042
pub output_path: Option<String>,
4143
pub progress_callback: Option<Arc<dyn Fn(DownloadState) + Send + Sync + 'static>>,
4244
pub extract_archive: bool,
45+
pub extract_dir: Option<String>,
4346
}
4447

4548
#[derive(Default)]
@@ -165,8 +168,22 @@ impl Downloader {
165168
}
166169

167170
if options.extract_archive {
168-
let extract_dir = output_path.parent().unwrap_or_else(|| Path::new("."));
169-
archive::extract_archive(output_path, extract_dir).await?;
171+
let extract_dir = match &options.extract_dir {
172+
Some(path) => {
173+
let path = Path::new(path);
174+
if !path.is_dir() {
175+
fs::create_dir_all(path).await?;
176+
}
177+
path.to_path_buf()
178+
}
179+
None => {
180+
let path = build_absolute_path(output_path)?;
181+
path.parent()
182+
.map(|p| p.to_path_buf())
183+
.unwrap_or_else(|| PathBuf::from("."))
184+
}
185+
};
186+
archive::extract_archive(output_path, &extract_dir).await?;
170187
}
171188

172189
Ok(filename)

src/platform.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ pub struct PlatformDownloadOptions {
125125
pub exclude_keywords: Vec<String>,
126126
pub exact_case: bool,
127127
pub extract_archive: bool,
128+
pub extract_dir: Option<String>,
128129
}
129130

130131
#[derive(Default)]
@@ -287,6 +288,7 @@ impl<P: ReleasePlatform> ReleaseHandler<P> {
287288
output_path: options.output_path,
288289
progress_callback: options.progress_callback,
289290
extract_archive: options.extract_archive,
291+
extract_dir: options.extract_dir,
290292
})
291293
.await?)
292294
}

src/utils.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::path::Path;
1+
use std::{
2+
env,
3+
path::{Path, PathBuf},
4+
};
25

36
use regex::Regex;
47
use reqwest::StatusCode;
@@ -92,6 +95,7 @@ pub fn matches_pattern(
9295
})
9396
}
9497

98+
// https://users.rust-lang.org/t/encode-decode-uri/90017/16
9599
pub fn decode_uri(s: impl AsRef<str>) -> String {
96100
let re = Regex::new(r"(%[A-Fa-f0-9]{2})+").unwrap();
97101

@@ -111,3 +115,12 @@ pub fn decode_uri(s: impl AsRef<str>) -> String {
111115
})
112116
.into_owned()
113117
}
118+
119+
pub fn build_absolute_path<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
120+
let path = path.as_ref();
121+
if path.is_absolute() {
122+
Ok(path.to_path_buf())
123+
} else {
124+
Ok(env::current_dir()?.join(path))
125+
}
126+
}

0 commit comments

Comments
 (0)