Open source Nest implementation
use std::env;

use rocket::fs::{relative, FileServer};
use rocket::{Build, Rocket};
use rocket_dyn_templates::Template;

#[macro_use]
extern crate rocket;

mod authz;
pub mod database;
mod repoman;

mod controllers;
pub mod models;

pub fn rocket() -> Rocket<Build> {
    let repo_storage_root =
        env::var("REPOSITORY_ROOT").expect("No REPOSITORY_ROOT env var exposed");

    rocket::build()
        .attach(database::stage())
        .attach(Template::fairing())
        .manage(repoman::new(repo_storage_root))
        .mount("/", controllers::routes())
        .mount("/", FileServer::from(relative!("static")))
}

/// this macro is lifted from the upstream unreleased code.
#[macro_export]
macro_rules! context {
    ($($key:ident $(: $value:expr)?),*$(,)?) => {{
        use rocket::serde::ser::{Serialize, Serializer, SerializeMap};
        use ::std::fmt::{Debug, Formatter};

        #[allow(non_camel_case_types)]
        struct ContextMacroCtxObject<$($key: Serialize),*> {
            $($key: $key),*
        }

        #[allow(non_camel_case_types)]
        impl<$($key: Serialize),*> Serialize for ContextMacroCtxObject<$($key),*> {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: Serializer,
            {
                let mut map = serializer.serialize_map(None)?;
                $(map.serialize_entry(stringify!($key), &self.$key)?;)*
                map.end()
            }
        }

        #[allow(non_camel_case_types)]
        impl<$($key: Debug + Serialize),*> Debug for ContextMacroCtxObject<$($key),*> {
            fn fmt(&self, f: &mut Formatter<'_>) -> ::std::fmt::Result {
                f.debug_struct("context!")
                    $(.field(stringify!($key), &self.$key))*
                    .finish()
            }
        }

        ContextMacroCtxObject {
            $($key $(: $value)?),*
        }
    }};
}