1use std::fs::File;
2use std::io::Write;
3use std::path::Path;
4use std::path::PathBuf;
5use std::process::Command;
6use std::process::Stdio;
7
8use color_eyre::eyre::eyre;
9
10pub enum CurlDownloaderOption<'a> {
11 PipeIntoZcat {
12 dest_path: &'a Path,
13 },
14 PipeIntoTar {
15 dest_dir: &'a Path,
16 dest_name: Option<&'a str>,
21 },
22 WriteTo {
23 dest_path: &'a Path,
24 },
25}
26
27pub fn run(url: &str, opt: &CurlDownloaderOption) -> color_eyre::Result<PathBuf> {
35 let mut curl_cmd = ytil_cmd::silent_cmd("curl");
36 let silent_flag = cfg!(debug_assertions).then(|| "S").unwrap_or("");
37 curl_cmd.args([&format!("-L{silent_flag}"), url]);
38
39 let target = match opt {
40 CurlDownloaderOption::PipeIntoZcat { dest_path } => {
41 let curl_stdout = get_cmd_stdout(&mut curl_cmd)?;
42
43 let output = Command::new("zcat").stdin(curl_stdout).output()?;
44 output.status.exit_ok()?;
45
46 let mut file = File::create(dest_path)?;
47 file.write_all(&output.stdout)?;
48
49 dest_path.into()
50 }
51 CurlDownloaderOption::PipeIntoTar { dest_dir, dest_name } => {
52 let curl_stdout = get_cmd_stdout(&mut curl_cmd)?;
53
54 let mut tar_cmd = Command::new("tar");
55 tar_cmd.args(["-xz", "-C", &dest_dir.to_string_lossy()]);
56 if let Some(dest_name) = dest_name {
57 tar_cmd.arg(dest_name);
58 }
59 tar_cmd.stdin(curl_stdout).status()?.exit_ok()?;
60
61 dest_name.map_or_else(|| dest_dir.into(), |dn| dest_dir.join(dn))
62 }
63 CurlDownloaderOption::WriteTo { dest_path } => {
64 curl_cmd.arg("--output");
65 curl_cmd.arg(dest_path);
66 curl_cmd.status()?.exit_ok()?;
67
68 dest_path.into()
69 }
70 };
71
72 Ok(target)
73}
74
75fn get_cmd_stdout(cmd: &mut Command) -> color_eyre::Result<Stdio> {
77 let stdout = cmd
78 .stdout(Stdio::piped())
79 .spawn()?
80 .stdout
81 .ok_or_else(|| eyre!("missing child stdout | cmd={cmd:#?}"))?;
82
83 Ok(Stdio::from(stdout))
84}