use ignore::WalkBuilder; use jacquard::types::blob::Blob; use miette::Diagnostic; use mime_guess::mime; use std::{collections::HashMap, path::PathBuf}; use thiserror::Error; pub type Sitemap = HashMap; #[derive(Debug)] pub struct SitemapNode { pub mime_type: String, pub blob: BlobRef, } #[derive(Debug)] pub enum BlobRef { Local(PathBuf), Remote(Blob<'static>), } #[derive(Debug, Error, Diagnostic)] pub enum SitemapErr { #[error("IO error: {}", .0)] IoErr(#[from] std::io::Error), #[error("Error finding files: {}", .0)] IgnoreErr(#[from] ignore::Error), #[error("Error normalising file paths: {}", .0)] StripPrefixErr(#[from] std::path::StripPrefixError), #[error("Found non UTF-8 path")] NotUTF8Path, } pub fn local_sitemap( dir: PathBuf, include_dotfiles: bool, use_gitignore: bool, ) -> miette::Result { let prefix = dir.canonicalize()?; let mut res = HashMap::new(); for file in WalkBuilder::new(dir) .hidden(!include_dotfiles) .git_ignore(use_gitignore) .git_exclude(use_gitignore) .git_global(use_gitignore) .follow_links(true) .build() { let file = file?; let metadata = file.metadata()?; if !metadata.is_file() { continue; }; // find the path of the files relative to the source directory // source dir `./dist`: // ./dist/index.html => index.html // ./dist/assets/cat.jpg => cat.jpg // etc let key = file.path().canonicalize()?; let key = key.strip_prefix(&prefix)?; let key = String::from(key.to_str().ok_or(SitemapErr::NotUTF8Path)?); let mime = mime_guess::from_path(&key); let mime = mime.first().unwrap_or(mime::APPLICATION_OCTET_STREAM); let mime = mime.essence_str(); res.insert( key, SitemapNode { mime_type: String::from(mime), blob: BlobRef::Local(file.path().to_owned()), }, ); } Ok(res) }