Skip to content

Commit

Permalink
do not embed during build
Browse files Browse the repository at this point in the history
  • Loading branch information
ngalaiko committed Feb 12, 2024
1 parent f7edcbc commit 2527381
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 78 deletions.
1 change: 0 additions & 1 deletion serve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ workspace = true

[build-dependencies]
shared = { path = "../shared" }
rust-embed = { version = "8.1.0", features = ["include-exclude"] }

[dependencies]
shared = { path = "../shared" }
Expand Down
189 changes: 112 additions & 77 deletions serve/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ use shared::{
types::{self, cocktails, entries, images, movies, places, records},
};

#[derive(rust_embed::RustEmbed)]
#[folder = "../assets/"]
struct Assets;

fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=../assets");
Expand All @@ -17,53 +13,37 @@ fn main() {
}
}

#[derive(Debug)]
enum BuildError {
Io(std::io::Error),
Var(std::env::VarError),
Entry(std::path::PathBuf, entries::FromError),
Cocktail(std::path::PathBuf, cocktails::FromError),
Movie(std::path::PathBuf, movies::FromError),
Record(std::path::PathBuf, records::FromError),
Place(std::path::PathBuf, places::FromError),
Image(std::path::PathBuf, images::ImageError),
}

impl std::fmt::Display for BuildError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BuildError::Io(error) => write!(f, "{error}"),
BuildError::Var(error) => write!(f, "{error}"),
BuildError::Entry(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Cocktail(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Movie(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Record(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Place(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Image(path, error) => write!(f, "{}: {error}", path.display()),
}
}
}

impl std::error::Error for BuildError {}

const WEBP_QUALITY: f32 = 95.0;

#[allow(clippy::too_many_lines)]
fn build() -> Result<(), BuildError> {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(BuildError::Var)?;
let output = std::path::PathBuf::from(manifest_dir).join("public");
fn build() -> Result<(), BuildError<'static>> {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
.map(std::path::PathBuf::from)
.map_err(|error| BuildError::Var("CARGO_MANIFEST_DIR", error))?;
let input = manifest_dir.join("../assets/");
let output = manifest_dir.join("public");

remove_dir_all(&output).map_err(BuildError::Io)?;
let asset_paths = walkdir(&input).map_err(|error| BuildError::WalkDir(input.clone(), error))?;

let assets = Assets::iter()
.filter_map(|asset_path| {
Assets::get(&asset_path)
.map(|asset| (std::path::PathBuf::from(asset_path.to_string()), asset))
let assets = asset_paths
.into_iter()
.map(|path| {
std::fs::read(&path)
.map(|data| (path.clone(), data))
.map_err(|error| BuildError::Read(path.clone(), error))
})
.map(|(path, asset)| assets::Asset {
path,
data: asset.data.to_vec(),
});
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.map(|(path, data)| assets::Asset {
path: path
.strip_prefix(&input)
.expect("always inside root")
.to_path_buf(),
data,
})
.collect::<Vec<_>>();

remove_dir_all(&output).map_err(|error| BuildError::Remove(output.clone(), error))?;

let (posts, assets): (Vec<_>, Vec<_>) = assets.into_iter().partition(|asset| {
asset.path.starts_with("posts/")
Expand Down Expand Up @@ -197,109 +177,116 @@ fn build() -> Result<(), BuildError> {
render::html::posts(posts.as_slice())
.into_string()
.as_bytes(),
)
.map_err(BuildError::Io)?;
)?;

write(
join(&output, "posts.atom"),
"redirect: /posts/index.atom".as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
write(
join(&output, "posts/index.atom"),
render::atom::posts(posts.as_slice()).to_string().as_bytes(),
)
.map_err(BuildError::Io)?;
)?;

write(
join(&output, "records/index.html"),
render::html::records(records.as_slice())
.into_string()
.as_bytes(),
)
.map_err(BuildError::Io)?;
)?;

for cover in record_covers {
write(join(&output, &cover.path), &cover.webp(WEBP_QUALITY)).map_err(BuildError::Io)?;
write(join(&output, &cover.path), &cover.webp(WEBP_QUALITY))?;
}

write(
join(&output, "cocktails/index.html"),
render::html::cocktails(cocktails.as_slice())
.into_string()
.as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
for image in cocktail_images {
write(join(&output, &image.path), &image.webp(WEBP_QUALITY)).map_err(BuildError::Io)?;
write(join(&output, &image.path), &image.webp(WEBP_QUALITY))?;
}

write(
join(&output, "restaurants_and_cafes/index.html"),
"redirect: /places/index.html".as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
write(
join(&output, "places/index.html"),
render::html::places(places.as_slice())
.into_string()
.as_bytes(),
)
.map_err(BuildError::Io)?;
)?;

write(
join(&output, "movies/index.html"),
render::html::movies(movies.as_slice())
.into_string()
.as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
for poster in movie_posters {
write(join(&output, &poster.path), &poster.webp(WEBP_QUALITY)).map_err(BuildError::Io)?;
write(join(&output, &poster.path), &poster.webp(WEBP_QUALITY))?;
}

for post in posts {
for alias in &post.frontmatter.aliases {
write(
join(&output, path::normalize(alias)),
render::html::redirect(&post.path).into_string().as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
}
write(
join(&output, &post.path),
render::html::post(&post).into_string().as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
}

for image in post_images {
write(join(&output, &image.path), &image.webp(WEBP_QUALITY)).map_err(BuildError::Io)?;
write(join(&output, &image.path), &image.webp(WEBP_QUALITY))?;
}

for cocktail in cocktails {
write(
join(&output, &cocktail.path),
render::html::cocktail(&cocktail).into_string().as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
}

for page in pages {
write(
join(&output, &page.path),
render::html::entry(&page).into_string().as_bytes(),
)
.map_err(BuildError::Io)?;
)?;
}

for rest in assets {
write(join(&output, &rest.path), &rest.data).map_err(BuildError::Io)?;
write(join(&output, &rest.path), &rest.data)?;
}

Ok(())
}

fn walkdir<P: AsRef<std::path::Path>>(root: P) -> Result<Vec<std::path::PathBuf>, std::io::Error> {
let root = root.as_ref();
let mut stack = vec![root.to_path_buf()];
let mut files = vec![];
while let Some(item) = stack.pop() {
if item.is_file() {
files.push(item);
} else if item.is_symlink() {
stack.push(item.read_link()?);
} else if item.is_dir() {
for item in std::fs::read_dir(item)? {
let item = item?;
stack.push(item.path());
}
}
}
Ok(files)
}

fn join<P, O>(path: P, other: O) -> std::path::PathBuf
where
P: AsRef<std::path::Path>,
Expand All @@ -313,14 +300,15 @@ where
path.as_ref().join(other)
}

fn write<P: AsRef<std::path::Path>>(path: P, data: &[u8]) -> Result<(), std::io::Error> {
fn write<'a, P: AsRef<std::path::Path>>(path: P, data: &[u8]) -> Result<(), BuildError<'a>> {
let path = path.as_ref();
if let Some(parent) = path.parent() {
if !parent.exists() {
std::fs::create_dir_all(parent)?;
std::fs::create_dir_all(parent)
.map_err(|error| BuildError::CreateDir(path.to_path_buf(), error))?;
}
}
std::fs::write(path, data)?;
std::fs::write(path, data).map_err(|error| BuildError::Write(path.to_path_buf(), error))?;
Ok(())
}

Expand All @@ -331,3 +319,50 @@ fn remove_dir_all<P: AsRef<std::path::Path>>(path: P) -> Result<(), std::io::Err
}
Ok(())
}

#[derive(Debug)]
enum BuildError<'a> {
Var(&'a str, std::env::VarError),
Remove(std::path::PathBuf, std::io::Error),
WalkDir(std::path::PathBuf, std::io::Error),
CreateDir(std::path::PathBuf, std::io::Error),
Read(std::path::PathBuf, std::io::Error),
Write(std::path::PathBuf, std::io::Error),
Entry(std::path::PathBuf, entries::FromError),
Cocktail(std::path::PathBuf, cocktails::FromError),
Movie(std::path::PathBuf, movies::FromError),
Record(std::path::PathBuf, records::FromError),
Place(std::path::PathBuf, places::FromError),
Image(std::path::PathBuf, images::ImageError),
}

impl std::fmt::Display for BuildError<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BuildError::Var(name, error) => write!(f, "env variale {name}: {error}"),
BuildError::WalkDir(path, error) => {
write!(f, "walking {}: {error}", path.display())
}
BuildError::CreateDir(path, error) => {
write!(f, "creating {}: {error}", path.display())
}
BuildError::Remove(path, error) => {
write!(f, "removing {}: {error}", path.display())
}
BuildError::Write(path, error) => {
write!(f, "writing {}: {error}", path.display())
}
BuildError::Read(path, error) => {
write!(f, "reading {}: {error}", path.display())
}
BuildError::Entry(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Cocktail(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Movie(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Record(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Place(path, error) => write!(f, "{}: {error}", path.display()),
BuildError::Image(path, error) => write!(f, "{}: {error}", path.display()),
}
}
}

impl std::error::Error for BuildError<'_> {}

0 comments on commit 2527381

Please sign in to comment.