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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
extern crate log;
use reqwest::header::{HeaderMap, HeaderValue, ACCEPT, USER_AGENT};
use reqwest::{Client, StatusCode};
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;
use provider::{Mirror, MirrorError, MirrorResult, Provider};
pub struct GitHub {
pub url: String,
pub org: String,
pub use_http: bool,
pub private_token: Option<String>,
pub useragent: String,
}
#[derive(Deserialize, Debug)]
struct Desc {
origin: String,
#[serde(default)]
skip: bool,
}
#[derive(Deserialize, Debug)]
struct Project {
description: Option<String>,
url: String,
ssh_url: String,
clone_url: String,
}
impl Provider for GitHub {
fn get_label(&self) -> String {
format!("{}/orgs/{}", self.url, self.org)
}
fn get_mirror_repos(&self) -> Result<Vec<MirrorResult>, String> {
let client = Client::new();
let use_http = self.use_http;
let mut headers = HeaderMap::new();
let useragent = HeaderValue::from_str(&self.useragent).expect("User agent invalid!");
headers.insert(USER_AGENT, useragent);
let accept = HeaderValue::from_static("application/vnd.github.v3+json");
headers.insert(ACCEPT, accept);
let url = format!("{}/orgs/{}/repos", self.url, self.org);
trace!("URL: {}", url);
let res = client
.get(&url)
.headers(headers)
.send()
.or_else(|e| Err(format!("Unable to connect to: {} ({})", url, e)))?;
if res.status() != StatusCode::OK {
if res.status() == StatusCode::UNAUTHORIZED {
return Err(format!(
"API call received unautorized ({}) for: {}. \
Please make sure the `GITHUB_PRIVATE_TOKEN` environment \
variable is set.",
res.status(),
url
));
} else {
return Err(format!(
"API call received invalid status ({}) for : {}",
res.status(),
url
));
}
}
let projects: Vec<Project> = serde_json::from_reader(res)
.or_else(|e| Err(format!("Unable to parse response as JSON ({:?})", e)))?;
let mut mirrors: Vec<MirrorResult> = Vec::new();
for p in projects {
match serde_yaml::from_str::<Desc>(&p.description.unwrap_or_default()) {
Ok(desc) => {
if desc.skip {
mirrors.push(Err(MirrorError::Skip(p.url)));
continue;
}
trace!("{0} -> {1}", desc.origin, p.ssh_url);
let destination = if use_http { p.clone_url } else { p.ssh_url };
let m = Mirror {
origin: desc.origin,
destination,
};
mirrors.push(Ok(m));
}
Err(e) => {
mirrors.push(Err(MirrorError::Description(p.url, e)));
}
}
}
Ok(mirrors)
}
}