1use std::error::Error;
2use std::fmt;
3use std::fs;
4use std::path::{Path,PathBuf};
5use log::{error,info};
6use reqwest;
7use reqwest::Url;
8
9#[derive(Clone)]
14pub struct Dependency {
15 name: String,
16 version: String
17}
18
19impl Dependency {
20 pub fn new(name: String, version: String) -> Self {
21 Dependency{name,version}
22 }
23 pub fn to_zipname(&self) -> String {
24 format!("{}-v{}.zip",self.name,self.version)
25 }
26
27 pub fn to_url(&self, base: &Url) -> Url {
28 let n = format!("{}/{}/{}",self.name,self.version,self.to_zipname());
29 base.join(&n).unwrap()
30 }
31}
32
33impl fmt::Display for Dependency {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 write!(f,"{}-{}",self.name,self.version)
36 }
37}
38
39#[derive(Clone,Debug,PartialEq)]
44pub struct PackageResolver<T: AsRef<Path>> {
45 dir: T,
47 url: Url
49}
50
51impl<T: AsRef<Path>> PackageResolver<T> {
52 pub fn new(dir: T, url: Url) -> Self {
56 fs::create_dir_all(dir.as_ref()).unwrap();
58 PackageResolver{dir,url}
60 }
61
62 pub fn resolve(&self, deps : &[Dependency]) -> Result<(),Box<dyn Error>> {
67 for dep in deps {
68 self.get(&dep)?;
69 }
70 Ok(())
72 }
73
74 pub fn get<'b>(&self, dep: &Dependency) -> Result<PathBuf,Box<dyn Error>> {
75 let mut zip = PathBuf::new();
77 zip.push(self.dir.as_ref());
78 zip.push(dep.to_zipname());
79 if !zip.as_path().exists() {
81 let url = dep.to_url(&self.url);
83 let response = reqwest::blocking::get(url.clone())?;
84 if response.status().is_success() {
86 info!("Downloaded {}",url.as_str());
87 fs::write(zip.as_path(),response.bytes()?)?;
88 } else {
89 error!("Downloading {} ({:?})",url.as_str(),response.status());
90 return Err(Box::new(ResolutionError{dep:(*dep).clone()}));
91 }
92 }
93 Ok(zip)
95 }
96}
97
98#[derive(Clone)]
103struct ResolutionError {
104 dep: Dependency
105}
106
107impl fmt::Display for ResolutionError {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 write!(f, "failed resolving package {}",self.dep)
110 }
111}
112
113impl fmt::Debug for ResolutionError {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 write!(f, "failed resolving package {}",self.dep)
116 }
117}
118
119impl Error for ResolutionError {}