Add 'serve::crate_relative!' for relative paths.

The macro generates crate-relative paths for easier serving of files
stored relative to the crate root.
This commit is contained in:
Sergio Benitez 2020-07-23 16:48:26 -07:00
parent 261cb400d1
commit a115eaa633
6 changed files with 61 additions and 23 deletions

View File

@ -21,6 +21,44 @@ use rocket::http::{Method, uri::Segments, ext::IntoOwned};
use rocket::handler::{Handler, Outcome}; use rocket::handler::{Handler, Outcome};
use rocket::response::{NamedFile, Redirect}; use rocket::response::{NamedFile, Redirect};
/// Generates a crate-relative version of `$path`.
///
/// This macro is primarily intended for use with [`StaticFiles`] to serve files
/// from a path relative to the crate root. The macro accepts one parameter,
/// `$path`, an absolute or relative path. It returns a path (an `&'static str`)
/// prefixed with the path to the crate root. Use `Path::new()` to retrieve an
/// `&'static Path`.
///
/// See the [relative paths `StaticFiles`
/// documentation](`StaticFiles`#relative-paths) for an example.
///
/// # Example
///
/// ```rust
/// use rocket_contrib::serve::{StaticFiles, crate_relative};
///
/// let manual = concat!(env!("CARGO_MANIFEST_DIR"), "/static");
/// let automatic = crate_relative!("static");
/// assert_eq!(manual, automatic);
///
/// use std::path::Path;
///
/// let manual = Path::new(env!("CARGO_MANIFEST_DIR")).join("static");
/// let automatic_1 = Path::new(crate_relative!("static"));
/// let automatic_2 = Path::new(crate_relative!("/static"));
/// assert_eq!(manual, automatic_1);
/// assert_eq!(automatic_1, automatic_2);
/// ```
#[macro_export]
macro_rules! crate_relative {
($path:expr) => {
concat!(env!("CARGO_MANIFEST_DIR"), "/", $path)
};
}
#[doc(inline)]
pub use crate_relative;
/// A bitset representing configurable options for the [`StaticFiles`] handler. /// A bitset representing configurable options for the [`StaticFiles`] handler.
/// ///
/// The valid options are: /// The valid options are:
@ -146,22 +184,22 @@ impl std::ops::BitOr for Options {
/// `/public/<directory>` will be handled by returning the contents of /// `/public/<directory>` will be handled by returning the contents of
/// `/static/<directory>/index.html`. /// `/static/<directory>/index.html`.
/// ///
/// `/static` is an absolute path. If your static files are stored relative to /// ## Relative Paths
/// your crate and your project is managed by Cargo, you should either use a ///
/// relative path and ensure that your server is started in the crate's root /// In the example above, `/static` is an absolute path. If your static files
/// directory or use the `CARGO_MANIFEST_DIR` environment variable to create an /// are stored relative to your crate and your project is managed by Cargo, use
/// absolute path relative to your crate root. For example, to serve files in /// the [`crate_relative!`] macro to obtain a path that is relative to your
/// the `static` subdirectory of your crate at `/`, you might write: /// crate's root. For example, to serve files in the `static` subdirectory of
/// your crate at `/`, you might write:
/// ///
/// ```rust,no_run /// ```rust,no_run
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::serve::StaticFiles; /// use rocket_contrib::serve::{StaticFiles, crate_relative};
/// ///
/// #[launch] /// #[launch]
/// fn rocket() -> rocket::Rocket { /// fn rocket() -> rocket::Rocket {
/// rocket::ignite() /// rocket::ignite().mount("/", StaticFiles::from(crate_relative!("/static")))
/// .mount("/", StaticFiles::from(concat!(env!("CARGO_MANIFEST_DIR"), "/static")))
/// } /// }
/// ``` /// ```
#[derive(Clone)] #[derive(Clone)]

View File

@ -1,17 +1,15 @@
#[cfg(feature = "serve")] #[cfg(feature = "serve")]
mod static_tests { mod static_tests {
use std::{io::Read, fs::File}; use std::{io::Read, fs::File};
use std::path::{Path, PathBuf}; use std::path::Path;
use rocket::{self, Rocket, Route}; use rocket::{self, Rocket, Route};
use rocket_contrib::serve::{StaticFiles, Options}; use rocket_contrib::serve::{StaticFiles, Options, crate_relative};
use rocket::http::Status; use rocket::http::Status;
use rocket::local::blocking::Client; use rocket::local::blocking::Client;
fn static_root() -> PathBuf { fn static_root() -> &'static Path {
Path::new(env!("CARGO_MANIFEST_DIR")) Path::new(crate_relative!("/tests/static"))
.join("tests")
.join("static")
} }
fn rocket() -> Rocket { fn rocket() -> Rocket {

View File

@ -3,7 +3,7 @@
use rocket::request::{Form, FormError, FormDataError}; use rocket::request::{Form, FormError, FormDataError};
use rocket::http::RawStr; use rocket::http::RawStr;
use rocket_contrib::serve::StaticFiles; use rocket_contrib::serve::{StaticFiles, crate_relative};
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
@ -37,5 +37,7 @@ fn sink(sink: Result<Form<FormInput<'_>>, FormError<'_>>) -> String {
#[launch] #[launch]
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", routes![sink]).mount("/", StaticFiles::from("static/")) rocket::ignite()
.mount("/", routes![sink])
.mount("/", StaticFiles::from(crate_relative!("/static")))
} }

View File

@ -6,7 +6,7 @@ use rocket::response::Redirect;
use rocket::request::{Form, FromFormValue}; use rocket::request::{Form, FromFormValue};
use rocket::http::RawStr; use rocket::http::RawStr;
use rocket_contrib::serve::StaticFiles; use rocket_contrib::serve::{StaticFiles, crate_relative};
#[derive(Debug)] #[derive(Debug)]
struct StrongPassword<'r>(&'r str); struct StrongPassword<'r>(&'r str);
@ -79,5 +79,5 @@ fn user_page(username: &RawStr) -> String {
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![user_page, login]) .mount("/", routes![user_page, login])
.mount("/", StaticFiles::from("static/")) .mount("/", StaticFiles::from(crate_relative!("/static")))
} }

View File

@ -2,7 +2,7 @@
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
use rocket_contrib::serve::StaticFiles; use rocket_contrib::serve::{StaticFiles, crate_relative};
// If we wanted or needed to serve files manually, we'd use `NamedFile`. Always // If we wanted or needed to serve files manually, we'd use `NamedFile`. Always
// prefer to use `StaticFiles`! // prefer to use `StaticFiles`!
@ -19,5 +19,5 @@ mod manual {
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![manual::icon]) .mount("/", routes![manual::icon])
.mount("/", StaticFiles::from("static")) .mount("/", StaticFiles::from(crate_relative!("/static")))
} }

View File

@ -11,7 +11,7 @@ use rocket::Rocket;
use rocket::fairing::AdHoc; use rocket::fairing::AdHoc;
use rocket::request::{Form, FlashMessage}; use rocket::request::{Form, FlashMessage};
use rocket::response::{Flash, Redirect}; use rocket::response::{Flash, Redirect};
use rocket_contrib::{templates::Template, serve::StaticFiles}; use rocket_contrib::{templates::Template, serve::{StaticFiles, crate_relative}};
use diesel::SqliteConnection; use diesel::SqliteConnection;
use crate::task::{Task, Todo}; use crate::task::{Task, Todo};
@ -106,7 +106,7 @@ fn rocket() -> Rocket {
rocket::ignite() rocket::ignite()
.attach(DbConn::fairing()) .attach(DbConn::fairing())
.attach(AdHoc::on_attach("Database Migrations", run_db_migrations)) .attach(AdHoc::on_attach("Database Migrations", run_db_migrations))
.mount("/", StaticFiles::from("static/")) .mount("/", StaticFiles::from(crate_relative!("/static")))
.mount("/", routes![index]) .mount("/", routes![index])
.mount("/todo", routes![new, toggle, delete]) .mount("/todo", routes![new, toggle, delete])
.attach(Template::fairing()) .attach(Template::fairing())