Skip to content

Commit 3d469fe

Browse files
committed
Code review
1 parent 7b39e47 commit 3d469fe

File tree

5 files changed

+268
-287
lines changed

5 files changed

+268
-287
lines changed

src/bin/cratesfyi.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ enum CommandLine {
5454
socket_addr: String,
5555

5656
/// Reload templates when they're changed
57-
#[structopt(long = "reload")]
58-
reload: bool,
57+
#[structopt(long = "reload-templates")]
58+
reload_templates: bool,
5959
},
6060

6161
/// Starts cratesfyi daemon
@@ -84,9 +84,9 @@ impl CommandLine {
8484
Self::Build(build) => build.handle_args(),
8585
Self::StartWebServer {
8686
socket_addr,
87-
reload,
87+
reload_templates,
8888
} => {
89-
Server::start(Some(&socket_addr), reload);
89+
Server::start(Some(&socket_addr), reload_templates);
9090
}
9191
Self::Daemon { foreground } => cratesfyi::utils::start_daemon(!foreground),
9292
Self::Database { subcommand } => subcommand.handle_args(),

src/web/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ pub struct Server {
363363

364364
impl Server {
365365
pub fn start(addr: Option<&str>, reload_templates: bool) -> Self {
366-
page::TEMPLATE_DATA.poke().expect("This returns Ok(())");
366+
// Initialize templates
367+
let _: &page::TemplateData = &*page::TEMPLATE_DATA;
367368
if reload_templates {
368369
page::TemplateData::start_template_reloading();
369370
}

src/web/page/handlebars.rs

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
//! Generic page struct
2+
3+
use handlebars_iron::Template;
4+
use iron::response::Response;
5+
use iron::{status, IronResult, Set};
6+
use serde::{
7+
ser::{SerializeStruct, Serializer},
8+
Serialize,
9+
};
10+
use serde_json::Value;
11+
use std::collections::BTreeMap;
12+
13+
lazy_static::lazy_static! {
14+
static ref RUSTC_RESOURCE_SUFFIX: String = load_rustc_resource_suffix()
15+
.unwrap_or_else(|_| "???".into());
16+
}
17+
18+
fn load_rustc_resource_suffix() -> Result<String, failure::Error> {
19+
let conn = crate::db::connect_db()?;
20+
21+
let res = conn.query(
22+
"SELECT value FROM config WHERE name = 'rustc_version';",
23+
&[],
24+
)?;
25+
if res.is_empty() {
26+
failure::bail!("missing rustc version");
27+
}
28+
29+
if let Some(Ok(vers)) = res.get(0).get_opt::<_, Value>("value") {
30+
if let Some(vers_str) = vers.as_str() {
31+
return Ok(crate::utils::parse_rustc_version(vers_str)?);
32+
}
33+
}
34+
35+
failure::bail!("failed to parse the rustc version");
36+
}
37+
38+
#[derive(Debug, Clone, PartialEq, Eq)]
39+
pub struct Page<T: Serialize> {
40+
title: Option<String>,
41+
content: T,
42+
status: status::Status,
43+
varss: BTreeMap<String, String>,
44+
varsb: BTreeMap<String, bool>,
45+
varsi: BTreeMap<String, i64>,
46+
rustc_resource_suffix: &'static str,
47+
}
48+
49+
impl<T: Serialize> Page<T> {
50+
pub fn new(content: T) -> Page<T> {
51+
Page {
52+
title: None,
53+
content,
54+
status: status::Ok,
55+
varss: BTreeMap::new(),
56+
varsb: BTreeMap::new(),
57+
varsi: BTreeMap::new(),
58+
rustc_resource_suffix: &RUSTC_RESOURCE_SUFFIX,
59+
}
60+
}
61+
62+
/// Sets a string variable
63+
pub fn set(mut self, var: &str, val: &str) -> Page<T> {
64+
self.varss.insert(var.to_owned(), val.to_owned());
65+
self
66+
}
67+
68+
/// Sets a boolean variable
69+
pub fn set_bool(mut self, var: &str, val: bool) -> Page<T> {
70+
self.varsb.insert(var.to_owned(), val);
71+
self
72+
}
73+
74+
/// Sets a boolean variable to true
75+
pub fn set_true(mut self, var: &str) -> Page<T> {
76+
self.varsb.insert(var.to_owned(), true);
77+
self
78+
}
79+
80+
/// Sets an integer variable
81+
pub fn set_int(mut self, var: &str, val: i64) -> Page<T> {
82+
self.varsi.insert(var.to_owned(), val);
83+
self
84+
}
85+
86+
/// Sets title of page
87+
pub fn title(mut self, title: &str) -> Page<T> {
88+
self.title = Some(title.to_owned());
89+
self
90+
}
91+
92+
/// Sets status code for response
93+
pub fn set_status(mut self, s: status::Status) -> Page<T> {
94+
self.status = s;
95+
self
96+
}
97+
98+
#[allow(clippy::wrong_self_convention)]
99+
pub fn to_resp(self, template: &str) -> IronResult<Response> {
100+
let mut resp = Response::new();
101+
let status = self.status;
102+
let temp = Template::new(template, self);
103+
resp.set_mut(temp).set_mut(status);
104+
105+
Ok(resp)
106+
}
107+
}
108+
109+
impl<T: Serialize> Serialize for Page<T> {
110+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
111+
where
112+
S: Serializer,
113+
{
114+
// Make sure that the length parameter passed to serde is correct by
115+
// adding the someness of the global alert to the total. `true`
116+
// is 1 and `false` is 0, so it increments if the value is some (and therefore
117+
// needs to be serialized)
118+
let mut state = serializer.serialize_struct(
119+
"Page",
120+
8 + crate::GLOBAL_ALERT.is_some() as usize + self.title.is_some() as usize,
121+
)?;
122+
123+
if let Some(ref title) = self.title {
124+
state.serialize_field("title", title)?;
125+
}
126+
127+
state.serialize_field("has_global_alert", &crate::GLOBAL_ALERT.is_some())?;
128+
if let Some(ref global_alert) = crate::GLOBAL_ALERT {
129+
state.serialize_field("global_alert", global_alert)?;
130+
}
131+
132+
state.serialize_field("content", &self.content)?;
133+
state.serialize_field("rustc_resource_suffix", self.rustc_resource_suffix)?;
134+
state.serialize_field("cratesfyi_version", crate::BUILD_VERSION)?;
135+
state.serialize_field(
136+
"cratesfyi_version_safe",
137+
&build_version_safe(crate::BUILD_VERSION),
138+
)?;
139+
state.serialize_field("varss", &self.varss)?;
140+
state.serialize_field("varsb", &self.varsb)?;
141+
state.serialize_field("varsi", &self.varsi)?;
142+
143+
state.end()
144+
}
145+
}
146+
147+
fn build_version_safe(version: &str) -> String {
148+
version.replace(" ", "-").replace("(", "").replace(")", "")
149+
}
150+
151+
#[cfg(test)]
152+
mod tests {
153+
use super::*;
154+
use crate::web::releases::{self, Release};
155+
use iron::Url;
156+
use serde_json::json;
157+
158+
#[test]
159+
fn serialize_page() {
160+
let time = time::get_time();
161+
162+
let mut release = Release::default();
163+
release.name = "lasso".into();
164+
release.version = "0.1.0".into();
165+
release.release_time = time.clone();
166+
167+
let mut varss = BTreeMap::new();
168+
varss.insert("test".into(), "works".into());
169+
let mut varsb = BTreeMap::new();
170+
varsb.insert("test2".into(), true);
171+
let mut varsi = BTreeMap::new();
172+
varsi.insert("test3".into(), 1337);
173+
174+
let page = Page {
175+
title: None,
176+
content: vec![release.clone()],
177+
status: status::Status::Ok,
178+
varss,
179+
varsb,
180+
varsi,
181+
rustc_resource_suffix: &*RUSTC_RESOURCE_SUFFIX,
182+
};
183+
184+
let correct_json = json!({
185+
"content": [{
186+
"name": "lasso",
187+
"version": "0.1.0",
188+
"description": null,
189+
"target_name": null,
190+
"rustdoc_status": false,
191+
"release_time": super::super::super::duration_to_str(time),
192+
"release_time_rfc3339": time::at(time).rfc3339().to_string(),
193+
"stars": 0
194+
}],
195+
"varss": { "test": "works" },
196+
"varsb": { "test2": true },
197+
"varsi": { "test3": 1337 },
198+
"rustc_resource_suffix": &*RUSTC_RESOURCE_SUFFIX,
199+
"cratesfyi_version": crate::BUILD_VERSION,
200+
"cratesfyi_version_safe": build_version_safe(crate::BUILD_VERSION),
201+
"has_global_alert": crate::GLOBAL_ALERT.is_some()
202+
});
203+
204+
assert_eq!(correct_json, serde_json::to_value(&page).unwrap());
205+
}
206+
207+
#[test]
208+
fn load_page_from_releases() {
209+
crate::test::wrapper(|env| {
210+
let db = env.db();
211+
db.fake_release().name("foo").version("0.1.0").create()?;
212+
let packages = releases::get_releases(&db.conn(), 1, 1, releases::Order::ReleaseTime);
213+
214+
let mut varsb = BTreeMap::new();
215+
varsb.insert("show_search_form".into(), true);
216+
varsb.insert("hide_package_navigation".into(), true);
217+
218+
let correct_page = Page {
219+
title: None,
220+
content: packages.clone(),
221+
status: status::Status::Ok,
222+
varss: BTreeMap::new(),
223+
varsb,
224+
varsi: BTreeMap::new(),
225+
rustc_resource_suffix: &RUSTC_RESOURCE_SUFFIX,
226+
};
227+
228+
let page = Page::new(packages)
229+
.set_true("show_search_form")
230+
.set_true("hide_package_navigation");
231+
232+
assert_eq!(page, correct_page);
233+
234+
Ok(())
235+
})
236+
}
237+
238+
#[test]
239+
fn build_version_url_safe() {
240+
let safe = format!(
241+
"https://docs.rs/builds/{}",
242+
build_version_safe(crate::BUILD_VERSION)
243+
);
244+
assert!(Url::parse(&safe).is_ok());
245+
}
246+
}

0 commit comments

Comments
 (0)