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"
|
||||
matches = "0.1"
|
||||
|
||||
[features]
|
||||
dynamic-assets = []
|
||||
|
||||
[profile]
|
||||
|
||||
[profile.release]
|
||||
|
|
102
src/assets.rs
102
src/assets.rs
|
@ -1,30 +1,82 @@
|
|||
use futures::Future;
|
||||
use web::{Resource, ResponseFuture};
|
||||
#[cfg(not(feature="dynamic-assets"))]
|
||||
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
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/themes.css"]
|
||||
#[mime = "text/css"]
|
||||
pub struct ThemesCss;
|
||||
// The CSS should be built to a single CSS file at compile time
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/themes.css"]
|
||||
#[mime = "text/css"]
|
||||
pub struct ThemesCss;
|
||||
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/style.css"]
|
||||
#[mime = "text/css"]
|
||||
pub struct StyleCss;
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/style.css"]
|
||||
#[mime = "text/css"]
|
||||
pub struct StyleCss;
|
||||
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/script.js"]
|
||||
#[mime = "application/javascript"]
|
||||
pub struct ScriptJs;
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/script.js"]
|
||||
#[mime = "application/javascript"]
|
||||
pub struct ScriptJs;
|
||||
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/search.js"]
|
||||
#[mime = "application/javascript"]
|
||||
pub struct SearchJs;
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/search.js"]
|
||||
#[mime = "application/javascript"]
|
||||
pub struct SearchJs;
|
||||
|
||||
// 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)
|
||||
#[derive(StaticResource)]
|
||||
#[filename = "assets/amatic-sc-v9-latin-regular.woff"]
|
||||
#[mime = "application/font-woff"]
|
||||
pub struct AmaticFont;
|
||||
// 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)
|
||||
// #[derive(StaticResource)]
|
||||
// #[filename = "assets/amatic-sc-v9-latin-regular.woff"]
|
||||
// #[mime = "application/font-woff"]
|
||||
// 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}";
|
||||
|
||||
#[cfg(all(not(debug_assertions), feature="dynamic-assets"))]
|
||||
compile_error!("dynamic-assets must not be used for production");
|
||||
|
||||
lazy_static! {
|
||||
pub static ref VERSION: String = || -> String {
|
||||
let mut components = Vec::<String>::new();
|
||||
|
@ -17,6 +20,9 @@ lazy_static! {
|
|||
#[cfg(test)]
|
||||
components.push("test".into());
|
||||
|
||||
#[cfg(feature="dynamic-assets")]
|
||||
components.push("dynamic-assets".into());
|
||||
|
||||
if let None = option_env!("CONTINUOUS_INTEGRATION") {
|
||||
components.push("local-build".into());
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ mod changes_resource;
|
|||
mod diff_resource;
|
||||
mod html_resource;
|
||||
mod new_article_resource;
|
||||
mod read_only_resource;
|
||||
mod search_resource;
|
||||
mod sitemap_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::html_resource::HtmlResource;
|
||||
pub use self::new_article_resource::NewArticleResource;
|
||||
pub use self::read_only_resource::ReadOnlyResource;
|
||||
pub use self::search_resource::SearchLookup;
|
||||
pub use self::sitemap_resource::SitemapResource;
|
||||
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 resources::*;
|
||||
use assets::*;
|
||||
use state::State;
|
||||
use web::{Lookup, Resource};
|
||||
|
||||
#[allow(unused)]
|
||||
use assets::*;
|
||||
|
||||
type BoxResource = Box<Resource + Sync + Send>;
|
||||
type ResourceFn = Box<Fn() -> BoxResource + Sync + Send>;
|
||||
|
||||
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!{
|
||||
"bsd-3-clause" => Box::new(|| Box::new(
|
||||
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 {
|
||||
pub fn new(state: State, show_authors: bool) -> WikiLookup {
|
||||
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))),
|
||||
("_about", Some(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)) =>
|
||||
Box::new(map_lookup(&ASSETS_MAP, asset)),
|
||||
("_by_id", Some(tail)) =>
|
||||
|
|
Loading…
Reference in a new issue