breb/lib.rs
1//! **b**log/**reb**log is oriented around the [`Blog`]: a collection of [`Serve`]s with some
2//! sitewide metadata. each [`Serve`] knows how to render the files in it, and the [`Blog`] maps
3//! the actual incoming requests to them. the responses are in the form of [`Response`]s, which
4//! map cleanly to http responses.
5// //!
6// //! you can create your list of [`Serve`]s however you want, but if you're familiar with the
7// //! blog/reblog config file, you might want to lean on the familiar blog/reblog [`Config`], which
8// //! is 1:1 with it -- it's how the CLI parses it normally. you can then [`expand`](Config::expand)
9// //! it into the serve list.
10// //!
11// //! finally, if your goal is to serve a **preview** of a blog, a simple HTTP server is included in
12// //! [`server`]. see the module docs for more info.
13
14#![warn(missing_docs)]
15
16pub mod parse;
17
18mod blog;
19mod dynamic;
20pub(crate) use dynamic::*;
21mod serve;
22
23pub use blog::{Author, Blog, Builder, ServedBuilder, FinishedBuilder};
24pub use serve::{
25 // base/shared types
26 Serve, Mount, Url, Dir,
27 // serve impls
28 AsIs, Feed, Posts, Pages,
29};
30
31pub mod config;
32pub use config::Config;
33
34/// all the imports you usually need. `use breb::quick::*` for best results.
35pub mod quick {
36 use std::{path::PathBuf, process::ExitCode};
37
38 pub use crate::{
39 // common config items
40 config::Stylesheet,
41 // utility types for building a `Blog`
42 Author, Blog, FinishedBuilder,
43 // serve implementations
44 AsIs, Feed, Pages, Posts,
45 };
46
47 /// a *very* basic cli that'll generate your blog and output some timing for fun.
48 ///
49 /// first, write a function that looks like:
50 ///
51 /// ```rs,no_run
52 /// use breb::quick::*;
53 /// fn make_blog(in_dir: PathBuf) -> FinishedBuilder {
54 /// Blog::builder()
55 /// .base_dir(in_dir)
56 /// .base_url("https://example.com/")
57 /// .name("examplecom example blog")
58 /// .author(Author::new("thor, a. u.").email("author@example.com"))
59 /// .serve(Feed::atom("/feed.xml"))
60 /// }
61 /// ```
62 ///
63 /// then, pass *that function*, not its return value, into this:
64 ///
65 /// ```rs
66 /// use breb::quick::*;
67 /// # fn make_blog(_: PathBuf) -> FinishedBuilder {
68 /// # Blog::builder()
69 /// # .base_dir("").base_url("").name("")
70 /// # .skip_author_check().skip_serve_check()
71 /// # }
72 /// fn main() {
73 /// boilerplate(make_blog);
74 /// }
75 /// ```
76 pub fn boilerplate(blog: impl FnOnce(PathBuf) -> FinishedBuilder) -> ExitCode {
77 let mut args = std::env::args().skip(1);
78 let in_dir = PathBuf::from(args.next().expect("must pass input directory"));
79 let out_dir = PathBuf::from(args.next().expect("must pass output directory"));
80 let start = std::time::Instant::now();
81 let blog = match blog(in_dir).build() {
82 Ok(blog) => {
83 println!("blog loaded in {}us, generating...", (std::time::Instant::now() - start).as_micros());
84 blog
85 }
86 Err(e) => {
87 println!("build failed: {e}");
88 return ExitCode::FAILURE;
89 }
90 };
91 let start = std::time::Instant::now();
92 match blog.generate(&out_dir) {
93 Ok(count) => {
94 println!("generated {count} pages in {}us", (std::time::Instant::now() - start).as_micros());
95 ExitCode::SUCCESS
96 }
97 Err(e) => {
98 println!("generation quit unexpectedly: {e}");
99 ExitCode::FAILURE
100 }
101 }
102 }
103}