1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
use std::fs;
use std::io::{self, BufRead};
use std::mem;
use std::path::PathBuf;
use anyhow::Error;
use hyper::Uri;
use structopt::StructOpt;
mod download;
use download::download;
#[derive(StructOpt, Debug)]
#[structopt(author, about)]
struct Args {
/// Read URLs from a file
#[structopt(short, long)]
input_file: Option<PathBuf>,
/// Specify output filename (will cause an error if multiple URLs are given)
#[structopt(short = "O", long)]
output_document: Option<PathBuf>,
/// Set output directory
#[structopt(short = "P", long, default_value = ".")]
directory_prefix: PathBuf,
/// User-Agent header to include
#[structopt(short = "U", long, default_value = concat!("webget/", env!("CARGO_PKG_VERSION")))]
user_agent: String,
/// The URLs to download
urls: Vec<Uri>,
}
#[tokio::main]
async fn main() -> Result<(), Vec<Error>> {
let (args, urls) = {
let mut args: Args = Args::from_args();
let mut urls = mem::take(&mut args.urls);
if let Some(input_file) = &args.input_file {
if let Ok(input_file) = fs::File::open(input_file) {
let input_file = io::BufReader::new(input_file);
let input_file_urls = input_file
.lines()
.filter_map(|line| line.ok().and_then(|line| line.parse().ok()));
urls.extend(input_file_urls);
}
}
(args, urls)
};
if urls.len() != 1 && args.output_document.is_some() {
panic!("can't use the same output file for multiple URLs!")
}
let download_handles = urls
.into_iter()
.map(|url| download(url, &args));
let downloads = futures::future::join_all(download_handles);
let download_errors = downloads.await
.into_iter()
.filter_map(|x| x.err())
.collect::<Vec<Error>>();
if download_errors.len() > 0 {
Err(download_errors)
} else {
Ok(())
}
}
|