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}