Add dynamic-assets feature to facilitate rapid feedback when working on the assets
This commit is contained in:
parent
8b0e58c24c
commit
963d70ff7a
6 changed files with 162 additions and 41 deletions
|
@ -79,6 +79,9 @@ git = "https://github.com/maghoff/pulldown-cmark.git"
|
||||||
indoc = "0.2"
|
indoc = "0.2"
|
||||||
matches = "0.1"
|
matches = "0.1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
dynamic-assets = []
|
||||||
|
|
||||||
[profile]
|
[profile]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
102
src/assets.rs
102
src/assets.rs
|
@ -1,30 +1,82 @@
|
||||||
use futures::Future;
|
#[cfg(not(feature="dynamic-assets"))]
|
||||||
use web::{Resource, ResponseFuture};
|
mod static_assets {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use futures::Future;
|
||||||
|
use web::{Resource, ResponseFuture};
|
||||||
|
|
||||||
// The CSS should be built to a single CSS file at compile time
|
// The CSS should be built to a single CSS file at compile time
|
||||||
#[derive(StaticResource)]
|
#[derive(StaticResource)]
|
||||||
#[filename = "assets/themes.css"]
|
#[filename = "assets/themes.css"]
|
||||||
#[mime = "text/css"]
|
#[mime = "text/css"]
|
||||||
pub struct ThemesCss;
|
pub struct ThemesCss;
|
||||||
|
|
||||||
#[derive(StaticResource)]
|
#[derive(StaticResource)]
|
||||||
#[filename = "assets/style.css"]
|
#[filename = "assets/style.css"]
|
||||||
#[mime = "text/css"]
|
#[mime = "text/css"]
|
||||||
pub struct StyleCss;
|
pub struct StyleCss;
|
||||||
|
|
||||||
#[derive(StaticResource)]
|
#[derive(StaticResource)]
|
||||||
#[filename = "assets/script.js"]
|
#[filename = "assets/script.js"]
|
||||||
#[mime = "application/javascript"]
|
#[mime = "application/javascript"]
|
||||||
pub struct ScriptJs;
|
pub struct ScriptJs;
|
||||||
|
|
||||||
#[derive(StaticResource)]
|
#[derive(StaticResource)]
|
||||||
#[filename = "assets/search.js"]
|
#[filename = "assets/search.js"]
|
||||||
#[mime = "application/javascript"]
|
#[mime = "application/javascript"]
|
||||||
pub struct SearchJs;
|
pub struct SearchJs;
|
||||||
|
|
||||||
// SIL Open Font License 1.1: http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
|
// SIL Open Font License 1.1: http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
|
||||||
// Copyright 2015 The Amatic SC Project Authors (contact@sansoxygen.com)
|
// Copyright 2015 The Amatic SC Project Authors (contact@sansoxygen.com)
|
||||||
#[derive(StaticResource)]
|
// #[derive(StaticResource)]
|
||||||
#[filename = "assets/amatic-sc-v9-latin-regular.woff"]
|
// #[filename = "assets/amatic-sc-v9-latin-regular.woff"]
|
||||||
#[mime = "application/font-woff"]
|
// #[mime = "application/font-woff"]
|
||||||
pub struct AmaticFont;
|
// pub struct AmaticFont;
|
||||||
|
|
||||||
|
type BoxResource = Box<Resource + Sync + Send>;
|
||||||
|
type ResourceFn = Box<Fn() -> BoxResource + Sync + Send>;
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref ASSETS_MAP: HashMap<&'static str, ResourceFn> = hashmap!{
|
||||||
|
// The CSS should be built to a single CSS file at compile time
|
||||||
|
ThemesCss::resource_name() =>
|
||||||
|
Box::new(|| Box::new(ThemesCss) as BoxResource) as ResourceFn,
|
||||||
|
|
||||||
|
StyleCss::resource_name() =>
|
||||||
|
Box::new(|| Box::new(StyleCss) as BoxResource) as ResourceFn,
|
||||||
|
|
||||||
|
ScriptJs::resource_name() =>
|
||||||
|
Box::new(|| Box::new(ScriptJs) as BoxResource) as ResourceFn,
|
||||||
|
|
||||||
|
SearchJs::resource_name() =>
|
||||||
|
Box::new(|| Box::new(SearchJs) as BoxResource) as ResourceFn,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature="dynamic-assets"))]
|
||||||
|
pub use self::static_assets::*;
|
||||||
|
|
||||||
|
#[cfg(feature="dynamic-assets")]
|
||||||
|
mod dynamic_assets {
|
||||||
|
pub struct ThemesCss;
|
||||||
|
impl ThemesCss {
|
||||||
|
pub fn resource_name() -> &'static str { "themes.css" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StyleCss;
|
||||||
|
impl StyleCss {
|
||||||
|
pub fn resource_name() -> &'static str { "style.css" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ScriptJs;
|
||||||
|
impl ScriptJs {
|
||||||
|
pub fn resource_name() -> &'static str { "script.js" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SearchJs;
|
||||||
|
impl SearchJs {
|
||||||
|
pub fn resource_name() -> &'static str { "search.js" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature="dynamic-assets")]
|
||||||
|
pub use self::dynamic_assets::*;
|
||||||
|
|
|
@ -7,6 +7,9 @@ pub const PROJECT_NAME: &str = env!("CARGO_PKG_NAME");
|
||||||
|
|
||||||
const SOFT_HYPHEN: &str = "\u{00AD}";
|
const SOFT_HYPHEN: &str = "\u{00AD}";
|
||||||
|
|
||||||
|
#[cfg(all(not(debug_assertions), feature="dynamic-assets"))]
|
||||||
|
compile_error!("dynamic-assets must not be used for production");
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref VERSION: String = || -> String {
|
pub static ref VERSION: String = || -> String {
|
||||||
let mut components = Vec::<String>::new();
|
let mut components = Vec::<String>::new();
|
||||||
|
@ -17,6 +20,9 @@ lazy_static! {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
components.push("test".into());
|
components.push("test".into());
|
||||||
|
|
||||||
|
#[cfg(feature="dynamic-assets")]
|
||||||
|
components.push("dynamic-assets".into());
|
||||||
|
|
||||||
if let None = option_env!("CONTINUOUS_INTEGRATION") {
|
if let None = option_env!("CONTINUOUS_INTEGRATION") {
|
||||||
components.push("local-build".into());
|
components.push("local-build".into());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ mod changes_resource;
|
||||||
mod diff_resource;
|
mod diff_resource;
|
||||||
mod html_resource;
|
mod html_resource;
|
||||||
mod new_article_resource;
|
mod new_article_resource;
|
||||||
|
mod read_only_resource;
|
||||||
mod search_resource;
|
mod search_resource;
|
||||||
mod sitemap_resource;
|
mod sitemap_resource;
|
||||||
mod temporary_redirect_resource;
|
mod temporary_redirect_resource;
|
||||||
|
@ -18,6 +19,7 @@ pub use self::changes_resource::{ChangesLookup, ChangesResource};
|
||||||
pub use self::diff_resource::{DiffLookup, DiffResource};
|
pub use self::diff_resource::{DiffLookup, DiffResource};
|
||||||
pub use self::html_resource::HtmlResource;
|
pub use self::html_resource::HtmlResource;
|
||||||
pub use self::new_article_resource::NewArticleResource;
|
pub use self::new_article_resource::NewArticleResource;
|
||||||
|
pub use self::read_only_resource::ReadOnlyResource;
|
||||||
pub use self::search_resource::SearchLookup;
|
pub use self::search_resource::SearchLookup;
|
||||||
pub use self::sitemap_resource::SitemapResource;
|
pub use self::sitemap_resource::SitemapResource;
|
||||||
pub use self::temporary_redirect_resource::TemporaryRedirectResource;
|
pub use self::temporary_redirect_resource::TemporaryRedirectResource;
|
||||||
|
|
38
src/resources/read_only_resource.rs
Normal file
38
src/resources/read_only_resource.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
use futures::Future;
|
||||||
|
use hyper::header::{ContentType, ContentLength, CacheControl, CacheDirective};
|
||||||
|
use hyper::server::*;
|
||||||
|
use hyper::StatusCode;
|
||||||
|
|
||||||
|
use web::{Resource, ResponseFuture};
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub struct ReadOnlyResource {
|
||||||
|
pub content_type: ::hyper::mime::Mime,
|
||||||
|
pub body: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resource for ReadOnlyResource {
|
||||||
|
fn allow(&self) -> Vec<::hyper::Method> {
|
||||||
|
use ::hyper::Method::*;
|
||||||
|
vec![Options, Head, Get]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn head(&self) -> ResponseFuture {
|
||||||
|
Box::new(::futures::finished(Response::new()
|
||||||
|
.with_status(StatusCode::Ok)
|
||||||
|
.with_header(ContentType(self.content_type.clone()))
|
||||||
|
.with_header(CacheControl(vec![
|
||||||
|
CacheDirective::MustRevalidate,
|
||||||
|
CacheDirective::NoStore,
|
||||||
|
]))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(self: Box<Self>) -> ResponseFuture {
|
||||||
|
Box::new(self.head().map(move |head|
|
||||||
|
head
|
||||||
|
.with_header(ContentLength(self.body.len() as u64))
|
||||||
|
.with_body(self.body.clone())
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,29 +8,16 @@ use percent_encoding::percent_decode;
|
||||||
use slug::slugify;
|
use slug::slugify;
|
||||||
|
|
||||||
use resources::*;
|
use resources::*;
|
||||||
use assets::*;
|
|
||||||
use state::State;
|
use state::State;
|
||||||
use web::{Lookup, Resource};
|
use web::{Lookup, Resource};
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
use assets::*;
|
||||||
|
|
||||||
type BoxResource = Box<Resource + Sync + Send>;
|
type BoxResource = Box<Resource + Sync + Send>;
|
||||||
type ResourceFn = Box<Fn() -> BoxResource + Sync + Send>;
|
type ResourceFn = Box<Fn() -> BoxResource + Sync + Send>;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref ASSETS_MAP: HashMap<&'static str, ResourceFn> = hashmap!{
|
|
||||||
// The CSS should be built to a single CSS file at compile time
|
|
||||||
ThemesCss::resource_name() =>
|
|
||||||
Box::new(|| Box::new(ThemesCss) as BoxResource) as ResourceFn,
|
|
||||||
|
|
||||||
StyleCss::resource_name() =>
|
|
||||||
Box::new(|| Box::new(StyleCss) as BoxResource) as ResourceFn,
|
|
||||||
|
|
||||||
ScriptJs::resource_name() =>
|
|
||||||
Box::new(|| Box::new(ScriptJs) as BoxResource) as ResourceFn,
|
|
||||||
|
|
||||||
SearchJs::resource_name() =>
|
|
||||||
Box::new(|| Box::new(SearchJs) as BoxResource) as ResourceFn,
|
|
||||||
};
|
|
||||||
|
|
||||||
static ref LICENSES_MAP: HashMap<&'static str, ResourceFn> = hashmap!{
|
static ref LICENSES_MAP: HashMap<&'static str, ResourceFn> = hashmap!{
|
||||||
"bsd-3-clause" => Box::new(|| Box::new(
|
"bsd-3-clause" => Box::new(|| Box::new(
|
||||||
HtmlResource::new(Some("../"), "The 3-Clause BSD License", include_str!("licenses/bsd-3-clause.html"))
|
HtmlResource::new(Some("../"), "The 3-Clause BSD License", include_str!("licenses/bsd-3-clause.html"))
|
||||||
|
@ -85,6 +72,35 @@ fn map_lookup(map: &HashMap<&str, ResourceFn>, path: &str) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn fs_lookup(root: &str, path: &str) ->
|
||||||
|
FutureResult<Option<BoxResource>, Box<::std::error::Error + Send + Sync>>
|
||||||
|
{
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
|
||||||
|
let extension = path.rsplitn(2, ".").next();
|
||||||
|
|
||||||
|
let content_type = match extension {
|
||||||
|
Some("css") => "text/css",
|
||||||
|
Some("js") => "application/javascript",
|
||||||
|
Some("woff") => "application/font-woff",
|
||||||
|
_ => "application/binary",
|
||||||
|
}.parse().unwrap();
|
||||||
|
|
||||||
|
let mut filename = root.to_string();
|
||||||
|
filename.push_str(path);
|
||||||
|
|
||||||
|
let mut f = File::open(&filename)
|
||||||
|
.unwrap_or_else(|_| panic!(format!("Not found: {}", filename)));
|
||||||
|
|
||||||
|
let mut body = Vec::new();
|
||||||
|
f.read_to_end(&mut body)
|
||||||
|
.expect("Unable to read file");
|
||||||
|
|
||||||
|
finished(Some(Box::new(ReadOnlyResource { content_type, body })))
|
||||||
|
}
|
||||||
|
|
||||||
impl WikiLookup {
|
impl WikiLookup {
|
||||||
pub fn new(state: State, show_authors: bool) -> WikiLookup {
|
pub fn new(state: State, show_authors: bool) -> WikiLookup {
|
||||||
let changes_lookup = ChangesLookup::new(state.clone(), show_authors);
|
let changes_lookup = ChangesLookup::new(state.clone(), show_authors);
|
||||||
|
@ -168,6 +184,10 @@ impl WikiLookup {
|
||||||
Box::new(finished(Some(Box::new(AboutResource::new()) as BoxResource))),
|
Box::new(finished(Some(Box::new(AboutResource::new()) as BoxResource))),
|
||||||
("_about", Some(license)) =>
|
("_about", Some(license)) =>
|
||||||
Box::new(map_lookup(&LICENSES_MAP, license)),
|
Box::new(map_lookup(&LICENSES_MAP, license)),
|
||||||
|
#[cfg(feature="dynamic-assets")]
|
||||||
|
("_assets", Some(asset)) =>
|
||||||
|
Box::new(fs_lookup(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/"), asset)),
|
||||||
|
#[cfg(not(feature="dynamic-assets"))]
|
||||||
("_assets", Some(asset)) =>
|
("_assets", Some(asset)) =>
|
||||||
Box::new(map_lookup(&ASSETS_MAP, asset)),
|
Box::new(map_lookup(&ASSETS_MAP, asset)),
|
||||||
("_by_id", Some(tail)) =>
|
("_by_id", Some(tail)) =>
|
||||||
|
|
Loading…
Reference in a new issue