mirror of
https://github.com/zyllian/webdog.git
synced 2025-05-10 02:26:42 -07:00
replace anyhow with eyre
This commit is contained in:
parent
00b5567769
commit
27bd18beea
12 changed files with 172 additions and 77 deletions
|
@ -42,7 +42,7 @@ pub struct BlogPostMetadata {
|
|||
|
||||
impl BlogPostMetadata {
|
||||
/// Helper to get the CDN URL to the blog post's header image.
|
||||
fn get_header_image(&self, site_config: &SiteConfig) -> anyhow::Result<String> {
|
||||
fn get_header_image(&self, site_config: &SiteConfig) -> eyre::Result<String> {
|
||||
Ok(site_config.cdn_url(&self.header_image_file)?.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ impl ResourceMethods<BlogPostTemplateData> for ResourceMetadata<BlogPostMetadata
|
|||
fn get_extra_resource_template_data(
|
||||
&self,
|
||||
site_config: &SiteConfig,
|
||||
) -> anyhow::Result<BlogPostTemplateData> {
|
||||
) -> eyre::Result<BlogPostTemplateData> {
|
||||
// TODO: render markdown
|
||||
Ok(BlogPostTemplateData {
|
||||
header_image: self.inner.get_header_image(site_config)?,
|
||||
|
@ -83,7 +83,7 @@ impl ResourceMethods<BlogPostTemplateData> for ResourceMetadata<BlogPostMetadata
|
|||
})
|
||||
}
|
||||
|
||||
fn get_head_data(&self, site_config: &SiteConfig) -> anyhow::Result<String> {
|
||||
fn get_head_data(&self, site_config: &SiteConfig) -> eyre::Result<String> {
|
||||
// TODO: update this so we're not just doing raw html injection lmao
|
||||
Ok(format!(
|
||||
r#"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Context;
|
||||
use eyre::Context;
|
||||
use gray_matter::{engine::YAML, Matter};
|
||||
use handlebars::Handlebars;
|
||||
use lol_html::{element, html_content::ContentType, HtmlRewriter, Settings};
|
||||
|
@ -70,7 +70,7 @@ impl<'a> SiteBuilder<'a> {
|
|||
}
|
||||
|
||||
/// Prepares the site builder for use and sets up the build directory.
|
||||
pub fn prepare(mut self) -> anyhow::Result<Self> {
|
||||
pub fn prepare(mut self) -> eyre::Result<Self> {
|
||||
if self.build_path.exists() {
|
||||
for entry in self.build_path.read_dir()? {
|
||||
let path = &entry?.path();
|
||||
|
@ -84,13 +84,13 @@ impl<'a> SiteBuilder<'a> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
std::fs::create_dir(&self.build_path).context("Failed to create build directory")?;
|
||||
std::fs::create_dir(&self.build_path).wrap_err("Failed to create build directory")?;
|
||||
}
|
||||
|
||||
for (template_name, template_path) in &self.site.template_index {
|
||||
self.reg
|
||||
.register_template_file(template_name, template_path)
|
||||
.context("Failed to register template file")?;
|
||||
.wrap_err("Failed to register template file")?;
|
||||
}
|
||||
|
||||
let root_path = self.site.site_path.join(ROOT_PATH);
|
||||
|
@ -104,21 +104,21 @@ impl<'a> SiteBuilder<'a> {
|
|||
|
||||
let images_path = self.build_path.join(crate::images::IMAGES_OUT_PATH);
|
||||
if !images_path.exists() {
|
||||
std::fs::create_dir(images_path).context("Failed to create images path")?;
|
||||
std::fs::create_dir(images_path).wrap_err("Failed to create images path")?;
|
||||
}
|
||||
|
||||
self.images_builder
|
||||
.load_all(&self)
|
||||
.context("Failed to load images metadata")?;
|
||||
.wrap_err("Failed to load images metadata")?;
|
||||
self.blog_builder
|
||||
.load_all(&self)
|
||||
.context("Failed to load blog metadata")?;
|
||||
.wrap_err("Failed to load blog metadata")?;
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Function to rewrite HTML wow.
|
||||
pub fn rewrite_html(&self, html: String) -> anyhow::Result<String> {
|
||||
pub fn rewrite_html(&self, html: String) -> eyre::Result<String> {
|
||||
let mut output = Vec::new();
|
||||
let mut rewriter = HtmlRewriter::new(
|
||||
Settings {
|
||||
|
@ -179,7 +179,7 @@ impl<'a> SiteBuilder<'a> {
|
|||
&self,
|
||||
page_metadata: PageMetadata,
|
||||
page_html: &str,
|
||||
) -> anyhow::Result<String> {
|
||||
) -> eyre::Result<String> {
|
||||
self.build_page_raw_with_extra_data(page_metadata, page_html, ())
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ impl<'a> SiteBuilder<'a> {
|
|||
page_metadata: PageMetadata,
|
||||
page_html: &str,
|
||||
extra_data: T,
|
||||
) -> anyhow::Result<String>
|
||||
) -> eyre::Result<String>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ impl<'a> SiteBuilder<'a> {
|
|||
}
|
||||
|
||||
/// Builds a standard page.
|
||||
pub fn build_page(&self, page_name: &str) -> anyhow::Result<()> {
|
||||
pub fn build_page(&self, page_name: &str) -> eyre::Result<()> {
|
||||
let page_path = self.site.page_index.get(page_name).expect("Missing page");
|
||||
|
||||
let input = std::fs::read_to_string(page_path)
|
||||
|
@ -260,14 +260,14 @@ impl<'a> SiteBuilder<'a> {
|
|||
}
|
||||
|
||||
/// Builds the Sass styles in the site.
|
||||
pub fn build_sass(&self) -> anyhow::Result<()> {
|
||||
pub fn build_sass(&self) -> eyre::Result<()> {
|
||||
let styles_path = self.build_path.join("styles");
|
||||
if !styles_path.exists() {
|
||||
std::fs::create_dir(&styles_path)?;
|
||||
}
|
||||
if self.serving {
|
||||
util::remove_dir_contents(&styles_path)
|
||||
.context("Failed to remove old contents of styles directory")?;
|
||||
.wrap_err("Failed to remove old contents of styles directory")?;
|
||||
}
|
||||
let sass_path = self.site.site_path.join(SASS_PATH);
|
||||
for sheet in &self.site.config.sass_styles {
|
||||
|
@ -277,7 +277,7 @@ impl<'a> SiteBuilder<'a> {
|
|||
Ok(mut css) => {
|
||||
if !self.serving {
|
||||
css = minifier::css::minify(&css)
|
||||
.map_err(|err| anyhow::anyhow!(err))?
|
||||
.map_err(|err| eyre::anyhow!(err))?
|
||||
.to_string();
|
||||
}
|
||||
std::fs::write(styles_path.join(sheet).with_extension("css"), css)
|
||||
|
@ -302,12 +302,12 @@ impl<'a> SiteBuilder<'a> {
|
|||
}
|
||||
|
||||
/// Builds the site's various image pages.
|
||||
pub fn build_images(&self) -> anyhow::Result<()> {
|
||||
pub fn build_images(&self) -> eyre::Result<()> {
|
||||
self.images_builder.build_all(self)
|
||||
}
|
||||
|
||||
/// Builds the site's blog.
|
||||
pub fn build_blog(&self) -> anyhow::Result<()> {
|
||||
pub fn build_blog(&self) -> eyre::Result<()> {
|
||||
self.blog_builder.build_all(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{blog::BlogPostMetadata, builder::SiteBuilder, resource::ResourceTemp
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum Extra {
|
||||
HtmlModification(fn(page: String, builder: &SiteBuilder) -> anyhow::Result<String>),
|
||||
HtmlModification(fn(page: String, builder: &SiteBuilder) -> eyre::Result<String>),
|
||||
}
|
||||
|
||||
/// Gets the extra for the given value.
|
||||
|
@ -17,7 +17,7 @@ pub fn get_extra(extra: &str) -> Option<Extra> {
|
|||
}
|
||||
|
||||
/// Extra to add a sidebar to the index page with recent blog posts on it.
|
||||
fn index(page: String, builder: &SiteBuilder) -> anyhow::Result<String> {
|
||||
fn index(page: String, builder: &SiteBuilder) -> eyre::Result<String> {
|
||||
#[derive(Debug, Serialize)]
|
||||
struct SidebarTemplateData<'r> {
|
||||
// resources: Vec<&'r ResourceMetadata<BlogPostMetadata>>,
|
||||
|
|
|
@ -53,7 +53,7 @@ impl ResourceMethods<ImageTemplateData> for ResourceMetadata<ImageMetadata> {
|
|||
fn get_extra_resource_template_data(
|
||||
&self,
|
||||
site_config: &SiteConfig,
|
||||
) -> anyhow::Result<ImageTemplateData> {
|
||||
) -> eyre::Result<ImageTemplateData> {
|
||||
Ok(ImageTemplateData {
|
||||
src: site_config.cdn_url(&self.inner.file)?.to_string(),
|
||||
})
|
||||
|
|
22
src/lib.rs
22
src/lib.rs
|
@ -13,7 +13,7 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use eyre::Context;
|
||||
use serde::Deserialize;
|
||||
use serving::get_name;
|
||||
use url::Url;
|
||||
|
@ -51,7 +51,7 @@ pub struct SiteConfig {
|
|||
|
||||
impl SiteConfig {
|
||||
/// Gets a CDN url from the given file name.
|
||||
pub fn cdn_url(&self, file: &str) -> anyhow::Result<Url> {
|
||||
pub fn cdn_url(&self, file: &str) -> eyre::Result<Url> {
|
||||
Ok(self.cdn_url.join(&self.s3_prefix)?.join(file)?)
|
||||
}
|
||||
}
|
||||
|
@ -86,24 +86,24 @@ pub struct Site {
|
|||
|
||||
impl Site {
|
||||
/// Creates a new site from the given path.
|
||||
pub fn new(site_path: &Path) -> anyhow::Result<Self> {
|
||||
pub fn new(site_path: &Path) -> eyre::Result<Self> {
|
||||
let config: SiteConfig = serde_yaml::from_str(
|
||||
&std::fs::read_to_string(site_path.join("config.yaml"))
|
||||
.context("Failed to read site config")?,
|
||||
.wrap_err("Failed to read site config")?,
|
||||
)
|
||||
.context("Failed to parse site config")?;
|
||||
.wrap_err("Failed to parse site config")?;
|
||||
|
||||
let mut template_index = HashMap::new();
|
||||
let templates_path = site_path.join(TEMPLATES_PATH);
|
||||
for entry in WalkDir::new(&templates_path).into_iter() {
|
||||
let entry = entry.context("Failed to read template entry")?;
|
||||
let entry = entry.wrap_err("Failed to read template entry")?;
|
||||
let path = entry.path();
|
||||
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "hbs" && entry.file_type().is_file() {
|
||||
let (_, name) = get_name(
|
||||
path.strip_prefix(&templates_path)
|
||||
.context("This really shouldn't have happened")?,
|
||||
.wrap_err("This really shouldn't have happened")?,
|
||||
);
|
||||
template_index.insert(name, path.to_owned());
|
||||
}
|
||||
|
@ -113,14 +113,14 @@ impl Site {
|
|||
let mut page_index = HashMap::new();
|
||||
let pages_path = site_path.join(PAGES_PATH);
|
||||
for entry in WalkDir::new(&pages_path).into_iter() {
|
||||
let entry = entry.context("Failed to read page entry")?;
|
||||
let entry = entry.wrap_err("Failed to read page entry")?;
|
||||
let path = entry.path();
|
||||
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "md" && entry.file_type().is_file() {
|
||||
page_index.insert(
|
||||
path.strip_prefix(&pages_path)
|
||||
.context("This really shouldn't have happened")?
|
||||
.wrap_err("This really shouldn't have happened")?
|
||||
.with_extension("")
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
|
@ -139,7 +139,7 @@ impl Site {
|
|||
}
|
||||
|
||||
/// Builds the site once.
|
||||
pub fn build_once(self) -> anyhow::Result<()> {
|
||||
pub fn build_once(self) -> eyre::Result<()> {
|
||||
let builder = SiteBuilder::new(self, false).prepare()?;
|
||||
|
||||
builder.site.build_all_pages(&builder)?;
|
||||
|
@ -151,7 +151,7 @@ impl Site {
|
|||
}
|
||||
|
||||
/// Helper method to build all available pages.
|
||||
fn build_all_pages(&self, builder: &SiteBuilder) -> anyhow::Result<()> {
|
||||
fn build_all_pages(&self, builder: &SiteBuilder) -> eyre::Result<()> {
|
||||
for page_name in self.page_index.keys() {
|
||||
builder.build_page(page_name)?;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn render_basic_link_list(
|
|||
builder: &SiteBuilder,
|
||||
links: Vec<Link>,
|
||||
title: &str,
|
||||
) -> anyhow::Result<String> {
|
||||
) -> eyre::Result<String> {
|
||||
let data = LinkTemplateData { links, title };
|
||||
let out = builder.reg.render("basic-link-list", &data)?;
|
||||
let out = builder.build_page_raw(
|
||||
|
|
|
@ -11,7 +11,10 @@ enum Mode {
|
|||
|
||||
#[cfg(feature = "serve")]
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
async fn main() -> eyre::Result<()> {
|
||||
#[cfg(feature = "color-eyre")]
|
||||
color_eyre::install()?;
|
||||
|
||||
let site = Site::new(&Path::new("site").canonicalize()?)?;
|
||||
|
||||
let mut mode = Mode::Build;
|
||||
|
@ -33,7 +36,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
#[cfg(not(feature = "serve"))]
|
||||
fn main() -> anyhow::Result<()> {
|
||||
fn main() -> eyre::Result<()> {
|
||||
let site = Site::new(&Path::new("site").canonicalize()?)?;
|
||||
site.build_once()?;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use eyre::Context;
|
||||
use itertools::Itertools;
|
||||
use pulldown_cmark::{Options, Parser};
|
||||
use rss::{validation::Validate, ChannelBuilder, ItemBuilder};
|
||||
|
@ -72,9 +72,9 @@ where
|
|||
{
|
||||
fn get_short_desc(&self) -> String;
|
||||
|
||||
fn get_extra_resource_template_data(&self, site_config: &SiteConfig) -> anyhow::Result<E>;
|
||||
fn get_extra_resource_template_data(&self, site_config: &SiteConfig) -> eyre::Result<E>;
|
||||
|
||||
fn get_head_data(&self, _site_config: &SiteConfig) -> anyhow::Result<String> {
|
||||
fn get_head_data(&self, _site_config: &SiteConfig) -> eyre::Result<String> {
|
||||
Ok(String::new())
|
||||
}
|
||||
}
|
||||
|
@ -158,14 +158,14 @@ where
|
|||
}
|
||||
|
||||
/// Loads resource metadata from the given path.
|
||||
fn load(builder: &SiteBuilder, path: &Path) -> anyhow::Result<(String, ResourceMetadata<M>)> {
|
||||
fn load(builder: &SiteBuilder, path: &Path) -> eyre::Result<(String, ResourceMetadata<M>)> {
|
||||
let id = Self::get_id(path);
|
||||
|
||||
let input = std::fs::read_to_string(path)?;
|
||||
let mut page = builder
|
||||
.matter
|
||||
.parse_with_struct::<ResourceMetadata<M>>(&input)
|
||||
.ok_or_else(|| anyhow::anyhow!("Failed to parse resource front matter"))?;
|
||||
.ok_or_else(|| eyre::anyhow!("Failed to parse resource front matter"))?;
|
||||
|
||||
let parser = Parser::new_ext(&page.content, Options::all());
|
||||
let mut html = String::new();
|
||||
|
@ -177,7 +177,7 @@ where
|
|||
}
|
||||
|
||||
/// Loads all resource metadata from the given config.
|
||||
pub fn load_all(&self, builder: &SiteBuilder) -> anyhow::Result<()> {
|
||||
pub fn load_all(&self, builder: &SiteBuilder) -> eyre::Result<()> {
|
||||
let mut lmd = self.loaded_metadata.borrow_mut();
|
||||
lmd.clear();
|
||||
for e in builder
|
||||
|
@ -213,7 +213,7 @@ where
|
|||
builder: &SiteBuilder,
|
||||
id: String,
|
||||
resource: &ResourceMetadata<M>,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
let out_path = self.build_path(&builder.build_path, &id);
|
||||
let out = {
|
||||
let data = ResourceTemplateData {
|
||||
|
@ -240,7 +240,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build_all(&self, builder: &SiteBuilder) -> anyhow::Result<()> {
|
||||
pub fn build_all(&self, builder: &SiteBuilder) -> eyre::Result<()> {
|
||||
let out_short = builder.build_path.join(&self.config.output_path_short);
|
||||
let out_long = builder.build_path.join(&self.config.output_path_long);
|
||||
|
||||
|
@ -276,7 +276,7 @@ where
|
|||
tag: Option<&str>,
|
||||
out_path: &Path,
|
||||
items_per_page: usize,
|
||||
) -> anyhow::Result<()>
|
||||
) -> eyre::Result<()>
|
||||
where
|
||||
M: Serialize,
|
||||
E: Serialize,
|
||||
|
@ -415,7 +415,7 @@ where
|
|||
.last_build_date(Some(OffsetDateTime::now_utc().format(&Rfc2822)?))
|
||||
.items(items)
|
||||
.build();
|
||||
channel.validate().context("Failed to validate RSS feed")?;
|
||||
channel.validate().wrap_err("Failed to validate RSS feed")?;
|
||||
let out = channel.to_string();
|
||||
std::fs::write(out_long.join("rss.xml"), out)?;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use eyre::Context;
|
||||
use futures::SinkExt;
|
||||
use hotwatch::{EventKind, Hotwatch};
|
||||
use warp::{
|
||||
|
@ -47,7 +47,7 @@ fn create(
|
|||
path: &Path,
|
||||
relative_path: &Path,
|
||||
build: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
if path.is_dir() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ fn create(
|
|||
builder.site.build_all_pages(builder)?;
|
||||
} else if let Ok(_sass_path) = relative_path.strip_prefix(SASS_PATH) {
|
||||
if build {
|
||||
builder.build_sass().context("Failed to rebuild Sass")?;
|
||||
builder.build_sass().wrap_err("Failed to rebuild Sass")?;
|
||||
}
|
||||
} else if let Ok(root_path) = relative_path.strip_prefix(ROOT_PATH) {
|
||||
std::fs::copy(path, builder.build_path.join(root_path))?;
|
||||
|
@ -94,7 +94,7 @@ fn create(
|
|||
}
|
||||
|
||||
/// Removes an existing resource.
|
||||
fn remove(builder: &mut SiteBuilder, path: &Path, relative_path: &Path) -> anyhow::Result<()> {
|
||||
fn remove(builder: &mut SiteBuilder, path: &Path, relative_path: &Path) -> eyre::Result<()> {
|
||||
if path.is_dir() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -111,9 +111,9 @@ fn remove(builder: &mut SiteBuilder, path: &Path, relative_path: &Path) -> anyho
|
|||
builder
|
||||
.site
|
||||
.build_all_pages(builder)
|
||||
.context("Failed to rebuild pages")?;
|
||||
.wrap_err("Failed to rebuild pages")?;
|
||||
} else if let Ok(_sass_path) = relative_path.strip_prefix(SASS_PATH) {
|
||||
builder.build_sass().context("Failed to rebuild Sass")?;
|
||||
builder.build_sass().wrap_err("Failed to rebuild Sass")?;
|
||||
} else if let Ok(root_path) = relative_path.strip_prefix(ROOT_PATH) {
|
||||
std::fs::remove_file(builder.build_path.join(root_path))?;
|
||||
} else if let Ok(_image_path) = relative_path.strip_prefix(crate::images::IMAGES_PATH) {
|
||||
|
@ -136,7 +136,7 @@ fn skip_path(builder: &SiteBuilder, path: &Path) -> bool {
|
|||
|
||||
impl Site {
|
||||
/// Serves the site for development. Don't use this in production.
|
||||
pub async fn serve(self) -> anyhow::Result<()> {
|
||||
pub async fn serve(self) -> eyre::Result<()> {
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
|
||||
|
||||
let mut builder = SiteBuilder::new(self, true).prepare()?;
|
||||
|
@ -149,11 +149,11 @@ impl Site {
|
|||
eprintln!("Failed to build page {}: {}", page_name, e);
|
||||
}
|
||||
}
|
||||
builder.build_sass().context("Failed to build Sass")?;
|
||||
builder.build_sass().wrap_err("Failed to build Sass")?;
|
||||
builder
|
||||
.build_images()
|
||||
.context("Failed to build image pages")?;
|
||||
builder.build_blog().context("Failed to build blog")?;
|
||||
.wrap_err("Failed to build image pages")?;
|
||||
builder.build_blog().wrap_err("Failed to build blog")?;
|
||||
|
||||
// Map of websocket connections
|
||||
let peers: Arc<Mutex<HashMap<SocketAddr, WebSocket>>> =
|
||||
|
@ -187,7 +187,7 @@ impl Site {
|
|||
println!("CHANGED - {:?}", relp);
|
||||
create(&mut builder, path, &relp, true)?;
|
||||
}
|
||||
Ok::<_, anyhow::Error>(true)
|
||||
Ok::<_, eyre::Error>(true)
|
||||
}
|
||||
}
|
||||
EventKind::Create(_) => {
|
||||
|
@ -235,7 +235,7 @@ impl Site {
|
|||
for (addr, peer) in peers.iter_mut() {
|
||||
let task = async {
|
||||
peer.send(Message::text("reload".to_string())).await?;
|
||||
Ok::<_, anyhow::Error>(())
|
||||
Ok::<_, eyre::Error>(())
|
||||
};
|
||||
to_remove.push(*addr);
|
||||
if let Err(e) = futures::executor::block_on(task) {
|
||||
|
@ -339,7 +339,7 @@ impl<'a> SiteBuilder<'a> {
|
|||
&mut self,
|
||||
template_name: &str,
|
||||
template_path: &Path,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
self.reg
|
||||
.register_template_file(template_name, template_path)?;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use std::path::Path;
|
||||
|
||||
/// Simple helper to remove the contents of a directory without removing the directory itself.
|
||||
pub fn remove_dir_contents(path: &Path) -> anyhow::Result<()> {
|
||||
pub fn remove_dir_contents(path: &Path) -> eyre::Result<()> {
|
||||
for entry in path.read_dir()? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue