diff --git a/contrib/lib/src/templates/fairing.rs b/contrib/lib/src/templates/fairing.rs index 7c89e127..71e138f1 100644 --- a/contrib/lib/src/templates/fairing.rs +++ b/contrib/lib/src/templates/fairing.rs @@ -23,6 +23,10 @@ mod context { crate fn context<'a>(&'a self) -> impl Deref + 'a { &self.0 } + + crate fn is_reloading(&self) -> bool { + false + } } } @@ -75,6 +79,10 @@ mod context { self.context.read().unwrap() } + crate fn is_reloading(&self) -> bool { + self.watcher.is_some() + } + fn context_mut<'a>(&'a self) -> impl DerefMut + 'a { self.context.write().unwrap() } diff --git a/contrib/lib/src/templates/metadata.rs b/contrib/lib/src/templates/metadata.rs index 64cd2894..f030337d 100644 --- a/contrib/lib/src/templates/metadata.rs +++ b/contrib/lib/src/templates/metadata.rs @@ -46,8 +46,13 @@ impl<'a> Metadata<'a> { /// # Example /// /// ```rust + /// # #![feature(proc_macro_hygiene, decl_macro)] + /// # #[macro_use] extern crate rocket; + /// # extern crate rocket_contrib; + /// # /// use rocket_contrib::templates::Metadata; /// + /// #[get("/")] /// fn handler(metadata: Metadata) { /// // Returns `true` if the template with name `"name"` was loaded. /// let loaded = metadata.contains_template("name"); @@ -56,6 +61,27 @@ impl<'a> Metadata<'a> { pub fn contains_template(&self, name: &str) -> bool { self.0.context().templates.contains_key(name) } + + /// Returns `true` if template reloading is enabled. + /// + /// # Example + /// + /// ```rust + /// # #![feature(proc_macro_hygiene, decl_macro)] + /// # #[macro_use] extern crate rocket; + /// # extern crate rocket_contrib; + /// # + /// use rocket_contrib::templates::Metadata; + /// + /// #[get("/")] + /// fn handler(metadata: Metadata) { + /// // Returns `true` if template reloading is enabled. + /// let reloading = metadata.reloading(); + /// } + /// ``` + pub fn reloading(&self) -> bool { + self.0.is_reloading() + } } /// Retrieves the template metadata. If a template fairing hasn't been attached, diff --git a/contrib/lib/tests/templates.rs b/contrib/lib/tests/templates.rs index a030a738..2c267715 100644 --- a/contrib/lib/tests/templates.rs +++ b/contrib/lib/tests/templates.rs @@ -22,6 +22,11 @@ mod templates_tests { } } + #[get("/is_reloading")] + fn is_reloading(md: Metadata) -> Option<()> { + if md.reloading() { Some(()) } else { None } + } + fn template_root() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")).join("tests").join("templates") } @@ -32,7 +37,7 @@ mod templates_tests { .expect("valid configuration"); ::rocket::custom(config).attach(Template::fairing()) - .mount("/", routes![template_check]) + .mount("/", routes![template_check, is_reloading]) } #[cfg(feature = "tera_templates")] @@ -142,8 +147,14 @@ mod templates_tests { let reload_path = template_root().join("hbs").join("reload.txt.hbs"); write_file(&reload_path, INITIAL_TEXT); - // verify that the initial content is correct + // set up the client. if we can't reload templates, then just quit let client = Client::new(rocket()).unwrap(); + let res = client.get("/is_reloading").dispatch(); + if res.status() != Status::Ok { + return; + } + + // verify that the initial content is correct let initial_rendered = Template::show(client.rocket(), RELOAD_TEMPLATE, ()); assert_eq!(initial_rendered, Some(INITIAL_TEXT.into())); diff --git a/contrib/lib/tests/templates/hbs/reload.txt.hbs b/contrib/lib/tests/templates/hbs/reload.txt.hbs index e76285e5..c72f08c3 100644 --- a/contrib/lib/tests/templates/hbs/reload.txt.hbs +++ b/contrib/lib/tests/templates/hbs/reload.txt.hbs @@ -1 +1 @@ -reload \ No newline at end of file +initial \ No newline at end of file diff --git a/core/codegen/tests/compile-test.rs b/core/codegen/tests/compile-test.rs index b137cd9c..3e41ebc0 100644 --- a/core/codegen/tests/compile-test.rs +++ b/core/codegen/tests/compile-test.rs @@ -5,7 +5,9 @@ use std::{io, fs::Metadata, time::SystemTime}; #[derive(Copy, Clone)] enum Kind { - Dynamic, Static + #[allow(dead_code)] + Dynamic, + Static } impl Kind { @@ -17,11 +19,6 @@ impl Kind { Kind::Static => ".rlib" } } - - fn prefix(self) -> &'static str { - #[cfg(windows)] { "" } - #[cfg(not(windows))] { "lib" } - } } fn target_path() -> PathBuf { @@ -52,7 +49,7 @@ fn best_time_for(metadata: &Metadata) -> SystemTime { fn extern_dep(name: &str, kind: Kind) -> io::Result { let deps_root = target_path().join("deps"); - let dep_name = format!("{}{}", kind.prefix(), name); + let dep_name = format!("lib{}", name); let mut dep_path: Option = None; for entry in deps_root.read_dir().expect("read_dir call failed") { diff --git a/core/codegen/tests/route.rs b/core/codegen/tests/route.rs index 0a2c038a..a496d36a 100644 --- a/core/codegen/tests/route.rs +++ b/core/codegen/tests/route.rs @@ -6,6 +6,7 @@ use std::fmt; use std::path::PathBuf; use rocket::{Request, Outcome::*}; +use rocket::http::ext::Normalize; use rocket::local::Client; use rocket::data::{self, Data, FromDataSimple}; use rocket::request::Form; @@ -48,7 +49,7 @@ fn post1( simple: Simple, ) -> String { let string = format!("{}, {}, {}, {}, {}, {}", - sky, name, a, query.field, path.display(), simple.0); + sky, name, a, query.field, path.normalized_str(), simple.0); let uri = uri!(post2: a, name.url_decode_lossy(), path, sky, query.into_inner()); @@ -65,7 +66,7 @@ fn post2( simple: Simple, ) -> String { let string = format!("{}, {}, {}, {}, {}, {}", - sky, name, a, query.field, path.display(), simple.0); + sky, name, a, query.field, path.normalized_str(), simple.0); let uri = uri!(post2: a, name.url_decode_lossy(), path, sky, query.into_inner()); diff --git a/core/http/src/ext.rs b/core/http/src/ext.rs index 0ea7a435..16294e29 100644 --- a/core/http/src/ext.rs +++ b/core/http/src/ext.rs @@ -98,3 +98,21 @@ impl<'a, B: 'static + ToOwned + ?Sized> IntoOwned for Cow<'a, B> { Cow::Owned(self.into_owned()) } } + +use std::path::Path; + +pub trait Normalize { + fn normalized_str(&self) -> Cow; +} + +impl> Normalize for T { + #[cfg(windows)] + fn normalized_str(&self) -> Cow { + self.as_ref().to_string_lossy().replace('\\', "/").into() + } + + #[cfg(not(windows))] + fn normalized_str(&self) -> Cow { + self.as_ref().to_string_lossy() + } +} diff --git a/core/http/src/uri/uri_display.rs b/core/http/src/uri/uri_display.rs index 9fa72a83..89c2f7a4 100644 --- a/core/http/src/uri/uri_display.rs +++ b/core/http/src/uri/uri_display.rs @@ -2,7 +2,7 @@ use std::fmt; use std::path::{Path, PathBuf}; use std::borrow::Cow; -use {RawStr, uri::Uri}; +use {RawStr, uri::Uri, ext::Normalize}; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; @@ -203,21 +203,21 @@ impl UriDisplay for String { } } -/// Percent-encodes each segment in the path. +/// Percent-encodes each segment in the path and normalizes separators. impl UriDisplay for PathBuf { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let string = self.to_string_lossy(); + let string = self.normalized_str(); let enc: Cow = utf8_percent_encode(&string, PATH_ENCODE_SET).into(); write!(f, "{}", enc) } } -/// Percent-encodes each segment in the path. +/// Percent-encodes each segment in the and normalizes separators. impl UriDisplay for Path { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let string = self.to_string_lossy(); + let string = self.normalized_str(); let enc: Cow = utf8_percent_encode(&string, PATH_ENCODE_SET).into(); write!(f, "{}", enc) } diff --git a/core/lib/src/config/config.rs b/core/lib/src/config/config.rs index ecd11fea..66546d63 100644 --- a/core/lib/src/config/config.rs +++ b/core/lib/src/config/config.rs @@ -927,7 +927,10 @@ impl Config { /// /// assert_eq!(config.root(), current_dir().unwrap()); /// assert_eq!(config.root_relative("abc"), config.root().join("abc")); + /// # #[cfg(not(windows))] /// assert_eq!(config.root_relative("/abc"), Path::new("/abc")); + /// # #[cfg(windows)] + /// # assert_eq!(config.root_relative("C:\\abc"), Path::new("C:\\abc")); /// ``` pub fn root_relative>(&self, path: P) -> PathBuf { let path = path.as_ref(); diff --git a/core/lib/src/ext.rs b/core/lib/src/ext.rs index aa68a935..8813b741 100644 --- a/core/lib/src/ext.rs +++ b/core/lib/src/ext.rs @@ -1,6 +1,4 @@ -use std::{fmt, io}; -use std::borrow::Cow; -use std::path::{Path, PathBuf, Component}; +use std::io; pub trait ReadExt: io::Read { fn read_max(&mut self, mut buf: &mut [u8]) -> io::Result { @@ -19,37 +17,3 @@ pub trait ReadExt: io::Read { } impl ReadExt for T { } - -pub struct NormalizedPath<'a>(&'a Path); - -impl<'a> fmt::Display for NormalizedPath<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fn to_str<'c>(c: &'c Component) -> Cow<'c, str> { - c.as_os_str().to_string_lossy() - } - - let mut components = self.0.components(); - match (components.next(), components.next()) { - (Some(Component::RootDir), Some(c)) => write!(f, "/{}", to_str(&c))?, - (Some(a), Some(b)) => write!(f, "{}/{}", to_str(&a), to_str(&b))?, - (Some(c), None) => write!(f, "{}", to_str(&c))?, - _ => return Ok(()) - }; - - for c in components { - write!(f, "/{}", to_str(&c))?; - } - - Ok(()) - } -} - -pub trait Normalize { - fn normalized(&self) -> NormalizedPath; -} - -impl> Normalize for T { - fn normalized(&self) -> NormalizedPath { - NormalizedPath(self.as_ref()) - } -} diff --git a/core/lib/src/lib.rs b/core/lib/src/lib.rs index 3a45bf12..8a8a4fff 100644 --- a/core/lib/src/lib.rs +++ b/core/lib/src/lib.rs @@ -116,7 +116,6 @@ extern crate isatty; #[cfg(test)] #[macro_use] extern crate lazy_static; #[doc(hidden)] #[macro_use] pub mod logger; -#[doc(hidden)] pub mod ext; pub mod local; pub mod request; pub mod response; @@ -142,6 +141,7 @@ mod router; mod rocket; mod codegen; mod catcher; +mod ext; #[doc(inline)] pub use response::Response; #[doc(inline)] pub use handler::{Handler, ErrorHandler}; diff --git a/core/lib/tests/route_guard.rs b/core/lib/tests/route_guard.rs index aa9a62e3..14f5d2b3 100644 --- a/core/lib/tests/route_guard.rs +++ b/core/lib/tests/route_guard.rs @@ -3,12 +3,12 @@ #[macro_use] extern crate rocket; use std::path::{Path, PathBuf}; -use rocket::ext::Normalize; +use rocket::http::ext::Normalize; use rocket::Route; #[get("/")] fn files(route: &Route, path: PathBuf) -> String { - Path::new(route.base()).join(path).normalized().to_string() + Path::new(route.base()).join(path).normalized_str().to_string() } mod route_guard_tests { diff --git a/examples/manual_routes/src/main.rs b/examples/manual_routes/src/main.rs index 13ea56cd..9f059d1a 100644 --- a/examples/manual_routes/src/main.rs +++ b/examples/manual_routes/src/main.rs @@ -3,7 +3,7 @@ extern crate rocket; #[cfg(test)] mod tests; -use std::io; +use std::{io, env}; use std::fs::File; use rocket::{Request, Handler, Route, Data, Catcher}; @@ -43,7 +43,7 @@ fn upload<'r>(req: &'r Request, data: Data) -> Outcome<'r> { return Outcome::failure(Status::BadRequest); } - let file = File::create("/tmp/upload.txt"); + let file = File::create(env::temp_dir().join("upload.txt")); if let Ok(mut file) = file { if let Ok(n) = io::copy(&mut data.open(), &mut file) { return Outcome::from(req, format!("OK: {} bytes uploaded.", n)); @@ -58,7 +58,7 @@ fn upload<'r>(req: &'r Request, data: Data) -> Outcome<'r> { } fn get_upload<'r>(req: &'r Request, _: Data) -> Outcome<'r> { - Outcome::from(req, File::open("/tmp/upload.txt").ok()) + Outcome::from(req, File::open(env::temp_dir().join("upload.txt")).ok()) } fn not_found_handler<'r>(req: &'r Request) -> response::Result<'r> { diff --git a/examples/raw_upload/src/main.rs b/examples/raw_upload/src/main.rs index 0808810b..1980973b 100644 --- a/examples/raw_upload/src/main.rs +++ b/examples/raw_upload/src/main.rs @@ -4,12 +4,12 @@ #[cfg(test)] mod tests; -use std::io; +use std::{io, env}; use rocket::Data; #[post("/upload", format = "plain", data = "")] fn upload(data: Data) -> io::Result { - data.stream_to_file("/tmp/upload.txt").map(|n| n.to_string()) + data.stream_to_file(env::temp_dir().join("upload.txt")).map(|n| n.to_string()) } #[get("/")] diff --git a/examples/raw_upload/src/tests.rs b/examples/raw_upload/src/tests.rs index 08ee278c..8e9a7b37 100644 --- a/examples/raw_upload/src/tests.rs +++ b/examples/raw_upload/src/tests.rs @@ -1,6 +1,7 @@ use rocket::local::Client; use rocket::http::{Status, ContentType}; +use std::env; use std::io::Read; use std::fs::{self, File}; @@ -16,7 +17,8 @@ fn test_index() { #[test] fn test_raw_upload() { // Delete the upload file before we begin. - let _ = fs::remove_file("/tmp/upload.txt"); + let upload_file = env::temp_dir().join("upload.txt"); + let _ = fs::remove_file(&upload_file); // Do the upload. Make sure we get the expected results. let client = Client::new(super::rocket()).unwrap(); @@ -30,7 +32,7 @@ fn test_raw_upload() { // Ensure we find the body in the /tmp/upload.txt file. let mut file_contents = String::new(); - let mut file = File::open("/tmp/upload.txt").expect("open upload.txt file"); + let mut file = File::open(&upload_file).expect("open upload.txt file"); file.read_to_string(&mut file_contents).expect("read upload.txt"); assert_eq!(&file_contents, UPLOAD_CONTENTS); }