diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-01-05 00:38:55 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-01-05 00:38:55 +0100 |
| commit | d7fef30ac3f539975ef9edbba8e0af4a4e9ff3de (patch) | |
| tree | 1e71dd131261a8f7a13d86d4dddd7d421e6a09f4 /src | |
| parent | d26464d12e41e8d53fca8d0e5f9cc6ac03e48f9a (diff) | |
Commit batch of lints to allow autofix
Diffstat (limited to 'src')
33 files changed, 473 insertions, 567 deletions
diff --git a/src/archiver/gemini.rs b/src/archiver/gemini.rs index 3b04bcf..b74d27b 100644 --- a/src/archiver/gemini.rs +++ b/src/archiver/gemini.rs @@ -1,20 +1,22 @@ +use crate::template::{find, parse, TemplateContext}; use std::fs::write; use std::io::{Error, ErrorKind::Other, Result}; -use std::path::PathBuf; -use crate::template::{find, parse, TemplateContext}; +use std::path::Path; const FILENAME: &str = "index.gmi"; -pub fn archive(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, context: &TemplateContext) -> Result<()> { - match find(template_directory, FILENAME) { - Some(template) => { - let parsed_template = parse(&template) - .ok_or_else(|| Error::new(Other, "Unable to parse Gemini Archive template"))?; - let rendered_template = parsed_template.render(context)?; - let location = target.join(FILENAME); - write(location, rendered_template)?; - }, - None => {} +pub fn archive( + _: &Path, + template_directory: &Path, + target: &Path, + context: &TemplateContext, +) -> Result<()> { + if let Some(template) = find(template_directory, FILENAME) { + let parsed_template = parse(&template) + .ok_or_else(|| Error::new(Other, "Unable to parse Gemini Archive template"))?; + let rendered_template = parsed_template.render(context)?; + let location = target.join(FILENAME); + write(location, rendered_template)?; } Ok(()) } diff --git a/src/archiver/gopher.rs b/src/archiver/gopher.rs index 28f4f46..fc0c04f 100644 --- a/src/archiver/gopher.rs +++ b/src/archiver/gopher.rs @@ -1,20 +1,22 @@ +use crate::template::{find, parse, TemplateContext}; use std::fs::write; use std::io::{Error, ErrorKind::Other, Result}; -use std::path::PathBuf; -use crate::template::{find, parse, TemplateContext}; +use std::path::Path; const FILENAME: &str = "index.gph"; -pub fn archive(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, context: &TemplateContext) -> Result<()> { - match find(template_directory, FILENAME) { - Some(template) => { - let parsed_template = parse(&template) - .ok_or_else(|| Error::new(Other, "Unable to parse Gopher Archive template"))?; - let rendered_template = parsed_template.render(context)?; - let location = target.join(FILENAME); - write(location, rendered_template)?; - }, - None => {} +pub fn archive( + _: &Path, + template_directory: &Path, + target: &Path, + context: &TemplateContext, +) -> Result<()> { + if let Some(template) = find(template_directory, FILENAME) { + let parsed_template = parse(&template) + .ok_or_else(|| Error::new(Other, "Unable to parse Gopher Archive template"))?; + let rendered_template = parsed_template.render(context)?; + let location = target.join(FILENAME); + write(location, rendered_template)?; } Ok(()) } diff --git a/src/archiver/mod.rs b/src/archiver/mod.rs index 6f0c284..4631bcb 100644 --- a/src/archiver/mod.rs +++ b/src/archiver/mod.rs @@ -1,39 +1,39 @@ -mod raw; mod gemini; mod gopher; +mod raw; +use crate::template::{TemplateContext, TemplateValue}; use std::collections::HashMap; use std::fs::read_dir; use std::io::Result; -use std::path::PathBuf; -use time::{OffsetDateTime, format_description::FormatItem, macros::format_description}; -use crate::template::{TemplateContext, TemplateValue}; +use std::path::{Path, PathBuf}; +use time::{format_description::FormatItem, macros::format_description, OffsetDateTime}; const DATE_FORMAT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day]"); struct ArchiveEntry { id: String, - slug: String + slug: String, } +type Archiver = fn(&Path, &Path, &Path, &TemplateContext) -> Result<()>; + impl ArchiveEntry { - pub fn to_template_context(archive_entries: &Vec<ArchiveEntry>) -> TemplateContext { + pub fn to_template_context(archive_entries: &[ArchiveEntry]) -> TemplateContext { let mut context = HashMap::new(); let archive_entries_collection = archive_entries .iter() - .map(|archive_entry| archive_entry.to_template_value()) + .map(ArchiveEntry::to_template_value) .collect(); context.insert( "archive_length".to_string(), - TemplateValue::Unsigned( - archive_entries.len().try_into().unwrap() - ) + TemplateValue::Unsigned(archive_entries.len().try_into().unwrap()), ); context.insert( "posts".to_string(), - TemplateValue::Collection(archive_entries_collection) + TemplateValue::Collection(archive_entries_collection), ); context @@ -42,21 +42,12 @@ impl ArchiveEntry { pub fn to_template_value(&self) -> TemplateContext { let mut context = HashMap::new(); - context.insert( - "id".to_string(), - TemplateValue::String(self.id.clone()) - ); + context.insert("id".to_string(), TemplateValue::String(self.id.clone())); - context.insert( - "slug".to_string(), - TemplateValue::String(self.slug.clone()) - ); + context.insert("slug".to_string(), TemplateValue::String(self.slug.clone())); if let Some(title) = self.title() { - context.insert( - "title".to_string(), - TemplateValue::String(title) - ); + context.insert("title".to_string(), TemplateValue::String(title)); } context @@ -64,17 +55,18 @@ impl ArchiveEntry { fn title(&self) -> Option<String> { let date = OffsetDateTime::from_unix_timestamp_nanos( - (self.id.parse::<u64>().ok()? * 1_000_000).into() - ).ok()?; + (self.id.parse::<u64>().ok()? * 1_000_000).into(), + ) + .ok()?; let short_date = date.format(&DATE_FORMAT).ok()?; - let title = self.slug.replace("-", " "); - Some(format!("{} {}", short_date, title)) + let title = self.slug.replace('-', " "); + Some(format!("{short_date} {title}")) } } fn read_archive(archive_directory: &PathBuf) -> Vec<ArchiveEntry> { let mut archive_entries = Vec::new(); - if let Ok(entries) = read_dir(&archive_directory) { + if let Ok(entries) = read_dir(archive_directory) { for entry in entries.filter_map(Result::ok) { let entry_path = entry.path(); let post_id = entry.file_name(); @@ -87,16 +79,18 @@ fn read_archive(archive_directory: &PathBuf) -> Vec<ArchiveEntry> { Some(extension) => { if extension == "gmi" { if let Some(slug) = candidate_path.file_stem() { - if let (Some(post_id), Some(slug)) = (post_id.to_str(), slug.to_str()) { + if let (Some(post_id), Some(slug)) = + (post_id.to_str(), slug.to_str()) + { archive_entries.push(ArchiveEntry { id: post_id.to_string(), - slug: slug.to_string() - }) + slug: slug.to_string(), + }); } } } - }, - _ => continue + } + _ => continue, } } } @@ -105,26 +99,29 @@ fn read_archive(archive_directory: &PathBuf) -> Vec<ArchiveEntry> { } } - archive_entries - .sort_by(|a, b| b.id.cmp(&a.id)); + archive_entries.sort_by(|a, b| b.id.cmp(&a.id)); archive_entries } - -pub fn archive(archive_directory: &PathBuf, template_directory: &PathBuf, output_directory: &PathBuf) -> Result<()> { +pub fn archive( + archive_directory: &PathBuf, + template_directory: &Path, + output_directory: &Path, +) -> Result<()> { let archivers = available_archivers(); let archive_entries = read_archive(archive_directory); let context = ArchiveEntry::to_template_context(&archive_entries); for archiver in archivers { - archiver(archive_directory, template_directory, output_directory, &context)?; + archiver( + archive_directory, + template_directory, + output_directory, + &context, + )?; } - return Ok(()) + Ok(()) } -fn available_archivers() -> Vec<fn(&PathBuf, &PathBuf, &PathBuf, &TemplateContext) -> Result<()>> { - vec![ - raw::archive, - gemini::archive, - gopher::archive - ] +fn available_archivers() -> Vec<Archiver> { + vec![raw::archive, gemini::archive, gopher::archive] } diff --git a/src/archiver/raw.rs b/src/archiver/raw.rs index 5099f2b..c3dc1cf 100644 --- a/src/archiver/raw.rs +++ b/src/archiver/raw.rs @@ -1,9 +1,14 @@ -use std::io::Result; -use std::path::PathBuf; use crate::template::TemplateContext; use crate::utils::recursively_copy; +use std::io::Result; +use std::path::Path; -pub fn archive(archive_directory: &PathBuf, _: &PathBuf, target: &PathBuf, _: &TemplateContext) -> Result<()> { +pub fn archive( + archive_directory: &Path, + _: &Path, + target: &Path, + _: &TemplateContext, +) -> Result<()> { if archive_directory.exists() { return recursively_copy(archive_directory, target); } diff --git a/src/command/add.rs b/src/command/add.rs index 02da0fb..d38d077 100644 --- a/src/command/add.rs +++ b/src/command/add.rs @@ -1,12 +1,7 @@ +use super::{generate::Generate, sync_down::SyncDown, sync_up::SyncUp, update::Update}; +use crate::configuration::Configuration; use std::fs::{create_dir_all, remove_dir_all, rename}; use std::io::Result; -use super::{ - generate::Generate, - sync_down::SyncDown, - sync_up::SyncUp, - update::Update -}; -use crate::configuration::Configuration; pub struct Add; @@ -21,7 +16,7 @@ impl super::Command for Add { vec![Box::new(SyncDown::new())] } - fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { + fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &str) -> Result<()> { create_dir_all(&configuration.posts_directory)?; for i in (0..configuration.max_posts - 1).rev() { let source = configuration.posts_directory.join(i.to_string()); @@ -41,7 +36,7 @@ impl super::Command for Add { vec![ Box::new(Update::new()), Box::new(Generate::new()), - Box::new(SyncUp::new()) + Box::new(SyncUp::new()), ] } diff --git a/src/command/add_remote.rs b/src/command/add_remote.rs index e9157f3..e5ca591 100644 --- a/src/command/add_remote.rs +++ b/src/command/add_remote.rs @@ -1,6 +1,6 @@ -use std::io::{Error, ErrorKind::Other, Result}; use crate::configuration::Configuration; use crate::remote::add; +use std::io::{Error, ErrorKind::Other, Result}; pub struct AddRemote; @@ -15,10 +15,19 @@ impl super::Command for AddRemote { vec![] } - fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { + fn execute( + &self, + input: Option<&String>, + configuration: &Configuration, + _: &str, + ) -> Result<()> { let input = input .ok_or_else(|| Error::new(Other, "You must provide a location for the remote."))?; - add(&configuration.config_directory, &configuration.remote_config, input) + add( + &configuration.config_directory, + &configuration.remote_config, + input, + ) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { diff --git a/src/command/generate.rs b/src/command/generate.rs index cc9e401..a79058d 100644 --- a/src/command/generate.rs +++ b/src/command/generate.rs @@ -1,13 +1,13 @@ -use std::fs::{create_dir_all, read_dir, remove_dir_all, File}; -use std::io::{Read, Result}; -use std::path::PathBuf; +use crate::archiver::archive; use crate::configuration::Configuration; use crate::constants::METADATA_FILENAME; -use crate::gemini_parser::parse; use crate::generator::generate; -use crate::archiver::archive; use crate::metadata::Metadata; use crate::post::Post; +use gema_texto::{gemini_parser::parse, html_renderer::render_html}; +use std::fs::{create_dir_all, read_dir, remove_dir_all, File}; +use std::io::{Read, Result}; +use std::path::Path; pub struct Generate; @@ -16,22 +16,22 @@ impl Generate { Generate } - fn read_posts(&self, posts_directory: &PathBuf, max_posts: u8) -> Vec<Post> { + fn read_posts(&self, posts_directory: &Path, max_posts: u8) -> Vec<Post> { let mut posts = Vec::new(); for i in 0..max_posts { - let post_directory = posts_directory.join(i.to_string()); - match self.read_post(&post_directory, i) { + let post_path = posts_directory.join(i.to_string()); + match self.read_post(&post_path, i) { Some(post) => posts.push(post), - None => continue + None => continue, } } posts } - fn find_blog_content(&self, post_directory: &PathBuf) -> Option<String> { - let entries = read_dir(&post_directory).ok()?; + fn find_blog_content(post_path: &Path) -> Option<String> { + let entries = read_dir(post_path).ok()?; for entry in entries.filter_map(Result::ok) { let entry_path = entry.path(); match entry_path.extension() { @@ -42,24 +42,24 @@ impl Generate { file.read_to_string(&mut contents).ok()?; return Some(contents); } - }, - None => continue + } + None => continue, } } None } - fn read_post(&self, post_directory: &PathBuf, index: u8) -> Option<Post> { + fn read_post(&self, post_directory: &Path, index: u8) -> Option<Post> { let metadata_path = post_directory.join(METADATA_FILENAME); let metadata = Metadata::read_or_create(&metadata_path); - let raw = self.find_blog_content(&post_directory)?; - let html = parse(&raw); + let raw = Generate::find_blog_content(post_directory)?; + let html = render_html(&parse(&raw)); Some(Post { metadata, index, html, - raw + raw, }) } } @@ -69,7 +69,7 @@ impl super::Command for Generate { vec![] } - fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { + fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &str) -> Result<()> { let _ = remove_dir_all(&configuration.blog_output_directory); create_dir_all(&configuration.blog_output_directory)?; @@ -78,7 +78,7 @@ impl super::Command for Generate { &configuration.static_directory, &configuration.templates_directory, &configuration.blog_output_directory, - &posts + &posts, )?; let _ = remove_dir_all(&configuration.archive_output_directory); @@ -86,9 +86,9 @@ impl super::Command for Generate { archive( &configuration.archive_directory, &configuration.templates_directory, - &configuration.archive_output_directory + &configuration.archive_output_directory, )?; - return Ok(()) + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { diff --git a/src/command/help.rs b/src/command/help.rs index 8d2a2c0..b682fc0 100644 --- a/src/command/help.rs +++ b/src/command/help.rs @@ -1,6 +1,6 @@ -use std::io::Result; use super::available_commands; use crate::configuration::Configuration; +use std::io::Result; pub struct Help; @@ -15,15 +15,15 @@ impl super::Command for Help { vec![] } - fn execute(&self, _: Option<&String>, _: &Configuration, _: &String) -> Result<()> { + fn execute(&self, _: Option<&String>, _: &Configuration, _: &str) -> Result<()> { let commands = available_commands(); println!("Usage:"); - println!(""); + println!(); for command in commands { print!("blog {} ", command.command()); println!("{}", command.help()); } - return Ok(()) + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { diff --git a/src/command/mod.rs b/src/command/mod.rs index 0c96e6f..2807193 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,37 +1,41 @@ pub mod add; +pub mod add_remote; pub mod generate; -pub mod update; +pub mod help; pub mod publish; pub mod publish_archive; -pub mod add_remote; pub mod remove_remote; -pub mod sync_up; -pub mod sync_down; pub mod status; +pub mod sync_down; +pub mod sync_up; +pub mod update; pub mod version; -pub mod help; - use std::io::Result; use add::Add; +use add_remote::AddRemote; use generate::Generate; -use update::Update; +use help::Help; use publish::Publish; use publish_archive::PublishArchive; -use add_remote::AddRemote; use remove_remote::RemoveRemote; -use sync_up::SyncUp; +use status::Status; use sync_down::SyncDown; +use sync_up::SyncUp; +use update::Update; use version::Version; -use status::Status; -use help::Help; use crate::configuration::Configuration; pub trait Command { fn before_dependencies(&self) -> Vec<Box<dyn Command>>; - fn execute(&self, input: Option<&String>, configuration: &Configuration, command: &String) -> Result<()>; + fn execute( + &self, + input: Option<&String>, + configuration: &Configuration, + command: &str, + ) -> Result<()>; fn after_dependencies(&self) -> Vec<Box<dyn Command>>; fn command(&self) -> &'static str; fn help(&self) -> &'static str; @@ -50,6 +54,6 @@ pub fn available_commands() -> Vec<Box<dyn Command>> { Box::new(SyncDown::new()), Box::new(Status::new()), Box::new(Version::new()), - Box::new(Help::new()) + Box::new(Help::new()), ] } diff --git a/src/command/publish.rs b/src/command/publish.rs index 34ca0d2..388792f 100644 --- a/src/command/publish.rs +++ b/src/command/publish.rs @@ -1,5 +1,5 @@ -use std::io::{Error, ErrorKind::Other, Result}; use crate::configuration::Configuration; +use std::io::{Error, ErrorKind::Other, Result}; use std::process::{Command, Stdio}; const COMMAND: &str = "rsync"; @@ -17,8 +17,12 @@ impl super::Command for Publish { vec![] } - fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { - + fn execute( + &self, + input: Option<&String>, + configuration: &Configuration, + _: &str, + ) -> Result<()> { let input = input .ok_or_else(|| Error::new(Other, "You must provide a location to publish the blog"))?; @@ -29,16 +33,18 @@ impl super::Command for Publish { .status() .map_err(|_| Error::new(Other, "Publishing requires rsync"))?; - Command::new(COMMAND) .arg("-r") - .arg(format!("{}/", &configuration.blog_output_directory.display())) + .arg(format!( + "{}/", + &configuration.blog_output_directory.display() + )) .arg(input.as_str()) .stdout(Stdio::null()) .stderr(Stdio::null()) .status() .map_err(|_| Error::new(Other, "Rsync failed to publish."))?; - return Ok(()) + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { diff --git a/src/command/publish_archive.rs b/src/command/publish_archive.rs index c727c16..96dda86 100644 --- a/src/command/publish_archive.rs +++ b/src/command/publish_archive.rs @@ -1,5 +1,5 @@ -use std::io::{Error, ErrorKind::Other, Result}; use crate::configuration::Configuration; +use std::io::{Error, ErrorKind::Other, Result}; use std::process::{Command, Stdio}; const COMMAND: &str = "rsync"; @@ -17,10 +17,15 @@ impl super::Command for PublishArchive { vec![] } - fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { - - let input = input - .ok_or_else(|| Error::new(Other, "You must provide a location to publish the archive"))?; + fn execute( + &self, + input: Option<&String>, + configuration: &Configuration, + _: &str, + ) -> Result<()> { + let input = input.ok_or_else(|| { + Error::new(Other, "You must provide a location to publish the archive") + })?; Command::new(COMMAND) .arg("--version") @@ -29,16 +34,18 @@ impl super::Command for PublishArchive { .status() .map_err(|_| Error::new(Other, "Publishing requires rsync"))?; - Command::new(COMMAND) .arg("-r") - .arg(format!("{}/", &configuration.archive_output_directory.display())) + .arg(format!( + "{}/", + &configuration.archive_output_directory.display() + )) .arg(input.as_str()) .stdout(Stdio::null()) .stderr(Stdio::null()) .status() .map_err(|_| Error::new(Other, "Rsync failed to publish."))?; - return Ok(()) + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { diff --git a/src/command/remove_remote.rs b/src/command/remove_remote.rs index 7590487..ee1dfde 100644 --- a/src/command/remove_remote.rs +++ b/src/command/remove_remote.rs @@ -1,6 +1,6 @@ -use std::io::Result; use crate::configuration::Configuration; use crate::remote::remove; +use std::io::Result; pub struct RemoveRemote; @@ -15,7 +15,7 @@ impl super::Command for RemoveRemote { vec![] } - fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { + fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &str) -> Result<()> { remove(&configuration.remote_config) } diff --git a/src/command/status/blog_status.rs b/src/command/status/blog_status.rs index df5256e..48f608a 100644 --- a/src/command/status/blog_status.rs +++ b/src/command/status/blog_status.rs @@ -1,6 +1,6 @@ +use crate::configuration::Configuration; use std::fs::read_dir; use std::path::PathBuf; -use crate::configuration::Configuration; pub fn status(configuration: &Configuration) -> String { let mut status_message = String::new(); @@ -9,16 +9,16 @@ pub fn status(configuration: &Configuration) -> String { // Main Configuration Locations let blog_count = count_entries(&configuration.posts_directory); - status_message.push_str(&format!("Number of posts in blog: {}\n", blog_count)); + status_message.push_str(&format!("Number of posts in blog: {blog_count}\n")); let archive_count = count_entries(&configuration.archive_directory); - status_message.push_str(&format!("Number of posts in archive: {}\n", archive_count)); + status_message.push_str(&format!("Number of posts in archive: {archive_count}\n")); status_message } fn count_entries(path: &PathBuf) -> String { match read_dir(path) { Ok(entries) => entries.filter_map(Result::ok).count().to_string(), - Err(_) => "0".to_string() + Err(_) => "0".to_string(), } } diff --git a/src/command/status/configuration_status.rs b/src/command/status/configuration_status.rs index 6d4e56a..96555c6 100644 --- a/src/command/status/configuration_status.rs +++ b/src/command/status/configuration_status.rs @@ -1,6 +1,6 @@ +use crate::configuration::Configuration; use std::fs; use std::path::PathBuf; -use crate::configuration::Configuration; pub fn status(configuration: &Configuration) -> String { let mut status_message = String::new(); @@ -9,12 +9,21 @@ pub fn status(configuration: &Configuration) -> String { status_message.push_str("\n## Directories\n"); // Main Configuration Locations - status_message.push_str(&get_directory_stats("Configuration", &configuration.config_directory)); + status_message.push_str(&get_directory_stats( + "Configuration", + &configuration.config_directory, + )); status_message.push_str(&get_directory_stats("Data", &configuration.data_directory)); - status_message.push_str(&get_directory_stats("Output", &configuration.output_directory)); + status_message.push_str(&get_directory_stats( + "Output", + &configuration.output_directory, + )); status_message.push_str("\n## Blog Settings\n"); - status_message.push_str(&format!("Number of posts to keep: {}\n", configuration.max_posts)); + status_message.push_str(&format!( + "Number of posts to keep: {}\n", + configuration.max_posts + )); status_message } @@ -24,7 +33,7 @@ fn get_directory_stats(label: &str, directory: &PathBuf) -> String { status_message.push_str(&format!("{}: {}. ", label, directory.display())); if directory.exists() { status_message.push_str("Exists "); - if fs::read_dir(&directory).is_ok() { + if fs::read_dir(directory).is_ok() { status_message.push_str("and is readable.\n"); } else { status_message.push_str("but is not readable.\n"); diff --git a/src/command/status/mod.rs b/src/command/status/mod.rs index e620f78..b92ef5f 100644 --- a/src/command/status/mod.rs +++ b/src/command/status/mod.rs @@ -1,8 +1,8 @@ -mod configuration_status; mod blog_status; +mod configuration_status; -use std::io::Result; use crate::configuration::Configuration; +use std::io::Result; pub struct Status; @@ -17,12 +17,12 @@ impl super::Command for Status { vec![] } - fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { + fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &str) -> Result<()> { let status_providers = available_status_providers(); for status_provider in status_providers { println!("{}\n----\n", status_provider(configuration)); } - return Ok(()) + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { @@ -39,8 +39,5 @@ impl super::Command for Status { } fn available_status_providers() -> Vec<fn(&Configuration) -> String> { - vec![ - configuration_status::status, - blog_status::status, - ] + vec![configuration_status::status, blog_status::status] } diff --git a/src/command/sync_down.rs b/src/command/sync_down.rs index eb8e57a..f9122d4 100644 --- a/src/command/sync_down.rs +++ b/src/command/sync_down.rs @@ -1,6 +1,6 @@ -use std::io::{Result}; use crate::configuration::Configuration; use crate::remote::sync_down; +use std::io::Result; pub struct SyncDown; @@ -15,16 +15,21 @@ impl super::Command for SyncDown { vec![] } - fn execute(&self, _: Option<&String>, configuration: &Configuration, command: &String) -> Result<()> { + fn execute( + &self, + _: Option<&String>, + configuration: &Configuration, + command: &str, + ) -> Result<()> { match sync_down(&configuration.data_directory, &configuration.remote_config) { - Ok(_) => {} + Ok(()) => {} Err(e) => { if command == self.command() { - return Err(e) + return Err(e); } } } - return Ok(()) + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { @@ -39,4 +44,3 @@ impl super::Command for SyncDown { "\t\t\t\tPulls from the git remote if configured" } } - diff --git a/src/command/sync_up.rs b/src/command/sync_up.rs index c44e0b0..b609c34 100644 --- a/src/command/sync_up.rs +++ b/src/command/sync_up.rs @@ -1,6 +1,6 @@ -use std::io::Result; use crate::configuration::Configuration; use crate::remote::sync_up; +use std::io::Result; pub struct SyncUp; @@ -15,16 +15,21 @@ impl super::Command for SyncUp { vec![] } - fn execute(&self, _: Option<&String>, configuration: &Configuration, command: &String) -> Result<()> { + fn execute( + &self, + _: Option<&String>, + configuration: &Configuration, + command: &str, + ) -> Result<()> { match sync_up(&configuration.data_directory, &configuration.remote_config) { - Ok(_) => {} + Ok(()) => {} Err(e) => { if command == self.command() { - return Err(e) + return Err(e); } } } - return Ok(()) + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { diff --git a/src/command/update.rs b/src/command/update.rs index 8a3d6de..54005f8 100644 --- a/src/command/update.rs +++ b/src/command/update.rs @@ -1,11 +1,11 @@ -use std::fs::{copy, create_dir_all, read_dir, remove_dir_all, write}; -use std::io::{Result, Error, ErrorKind}; -use std::path::PathBuf; -use super::{sync_down::SyncDown, generate::Generate, sync_up::SyncUp}; +use super::{generate::Generate, sync_down::SyncDown, sync_up::SyncUp}; use crate::configuration::Configuration; use crate::constants::METADATA_FILENAME; use crate::metadata::Metadata; use serde_json; +use std::fs::{copy, create_dir_all, read_dir, remove_dir_all, write}; +use std::io::{Error, ErrorKind, Result}; +use std::path::{Path, PathBuf}; pub struct Update; @@ -14,8 +14,9 @@ impl Update { Update } - fn copy_post(&self, source: &PathBuf, target: &PathBuf) -> Result<()> { - let post_name = source.file_name() + fn copy_post(source: &PathBuf, target: &Path) -> Result<()> { + let post_name = source + .file_name() .ok_or_else(|| Error::new(ErrorKind::InvalidInput, "Could not get post filename."))?; let target_post = target.join(post_name); @@ -23,13 +24,13 @@ impl Update { Ok(()) } - fn write_metadata(&self, metadata: &Metadata, metadata_location: &PathBuf) -> Result<()> { + fn write_metadata(metadata: &Metadata, metadata_location: &PathBuf) -> Result<()> { let serialized_metadata = serde_json::to_string(&metadata)?; write(metadata_location, serialized_metadata)?; Ok(()) } - fn archive(&self, source: &PathBuf, target: &PathBuf) -> Result<()> { + fn archive(source: &PathBuf, target: &Path) -> Result<()> { let entries = read_dir(source)?; for entry in entries { let entry = entry?; @@ -39,7 +40,7 @@ impl Update { let entry_target = target.join(entry_name); if entry_type.is_dir() { - self.archive(&entry_source, &entry_target)?; + Update::archive(&entry_source, &entry_target)?; } else { copy(&entry_source, &entry_target)?; } @@ -54,12 +55,21 @@ impl super::Command for Update { vec![Box::new(SyncDown::new())] } - fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> { - let input = input - .ok_or_else(|| Error::new(ErrorKind::InvalidInput, "You must provide a path to a post"))?; + fn execute( + &self, + input: Option<&String>, + configuration: &Configuration, + _: &str, + ) -> Result<()> { + let input = input.ok_or_else(|| { + Error::new(ErrorKind::InvalidInput, "You must provide a path to a post") + })?; let post_location = PathBuf::from(input); if !post_location.exists() { - return Err(Error::new(ErrorKind::NotFound, "The path provided does not exist")); + return Err(Error::new( + ErrorKind::NotFound, + "The path provided does not exist", + )); } // Step 1. Write into the ephemeral posts @@ -73,8 +83,8 @@ impl super::Command for Update { let _ = remove_dir_all(&first_post_path); create_dir_all(&first_post_path)?; - self.copy_post(&post_location, &first_post_path)?; - self.write_metadata(&metadata, &metadata_file_path)?; + Update::copy_post(&post_location, &first_post_path)?; + Update::write_metadata(&metadata, &metadata_file_path)?; // Step 2. Write into the archive @@ -84,15 +94,12 @@ impl super::Command for Update { let _ = remove_dir_all(&post_archive_path); create_dir_all(&post_archive_path)?; - self.archive(&first_post_path, &post_archive_path)?; - return Ok(()) + Update::archive(&first_post_path, &post_archive_path)?; + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { - vec![ - Box::new(Generate::new()), - Box::new(SyncUp::new()) - ] + vec![Box::new(Generate::new()), Box::new(SyncUp::new())] } fn command(&self) -> &'static str { @@ -103,4 +110,3 @@ impl super::Command for Update { "<path_to_post>\t\tUpdates latest blog post" } } - diff --git a/src/command/version.rs b/src/command/version.rs index e566c5a..94eb92e 100644 --- a/src/command/version.rs +++ b/src/command/version.rs @@ -1,5 +1,5 @@ -use std::io::Result; use crate::configuration::Configuration; +use std::io::Result; pub struct Version; @@ -14,10 +14,10 @@ impl super::Command for Version { vec![] } - fn execute(&self, _: Option<&String>, _: &Configuration, _: &String) -> Result<()> { + fn execute(&self, _: Option<&String>, _: &Configuration, _: &str) -> Result<()> { let version = env!("CARGO_PKG_VERSION"); - println!("{}", version); - return Ok(()) + println!("{version}"); + Ok(()) } fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> { diff --git a/src/configuration.rs b/src/configuration.rs index 65eb0ba..1c0e905 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -21,30 +21,25 @@ pub struct Configuration { // Derived directories: Output pub blog_output_directory: PathBuf, - pub archive_output_directory: PathBuf + pub archive_output_directory: PathBuf, } impl Configuration { - - pub fn new() -> Self { + pub fn new() -> Self { let config_directory = Configuration::directory( "BLOG_CONFIG_DIRECTORY", "XDG_CONFIG_HOME", ".config", - "blog" + "blog", ); let data_directory = Configuration::directory( "BLOG_DATA_DIRECTORY", "XDG_DATA_HOME", ".local/share", - "blog" - ); - let output_directory = Configuration::directory( - "BLOG_OUTPUT_DIRECTORY", - "XDG_CACHE_HOME", - ".cache", - "blog" + "blog", ); + let output_directory = + Configuration::directory("BLOG_OUTPUT_DIRECTORY", "XDG_CACHE_HOME", ".cache", "blog"); let max_posts: u8 = env::var("BLOG_MAX_POSTS") .ok() @@ -72,20 +67,29 @@ impl Configuration { static_directory, templates_directory, blog_output_directory, - archive_output_directory + archive_output_directory, } } - fn directory(user_override: &str, default_value: &str, home_fallback: &str, path: &str) -> PathBuf { + fn directory( + user_override: &str, + default_value: &str, + home_fallback: &str, + path: &str, + ) -> PathBuf { match env::var(user_override) { Ok(directory) => PathBuf::from(directory), Err(_) => match env::var(default_value) { Ok(directory) => PathBuf::from(directory), Err(_) => match env::var("HOME") { Ok(directory) => PathBuf::from(directory).join(home_fallback), - Err(_) => panic!("Could not find required directory, {} or {} should be set and readable.", user_override, default_value), + Err(_) => panic!( + "Could not find required directory, {} or {} should be set and readable.", + user_override, default_value + ), }, }, - }.join(path) + } + .join(path) } } diff --git a/src/gemini_parser.rs b/src/gemini_parser.rs deleted file mode 100644 index 3414ea7..0000000 --- a/src/gemini_parser.rs +++ /dev/null @@ -1,225 +0,0 @@ -// TAKEN FROM PAGE. Need to move to a common source. - pub fn parse(source: &str) -> String { - - let lines = source.split("\n"); - let mut is_preformatted = false; - - let mut block_label: Option<String> = None; - let mut html: String = "".to_owned(); - let mut current_line_type: Option<LineType> = None; - - let mut heading_stack: Vec<u8> = Vec::new(); - for line in lines { - let mut line_type = LineType::Blank; - if line.char_indices().count() > 2 { - let mut end = line.len(); - if line.char_indices().count() > 3 { - end = line.char_indices().map(|(i, _)| i).nth(3).unwrap(); - } - line_type = identify_line(&line[..end], is_preformatted); - } - match line_type { - LineType::PreformattedToggle => { - is_preformatted = !is_preformatted; - if is_preformatted && line.char_indices().count() > 3 { - block_label = Some(get_partial_line_content(&line_type, line)); - } else { - block_label = None; - } - }, - _ => { - // Close previous block if needed - if let Some(line) = ¤t_line_type { - if line != &line_type && is_block(line) { - html.push_str(get_line_closer(line)); - } - } - - // Blocks - if is_block(&line_type) { - if let Some(line) = ¤t_line_type { - if line != &line_type { - html.push_str(&get_line_opener(&line_type, block_label.as_ref())); - } - } else { - html.push_str(&get_line_opener(&line_type, None)); - } - - let line_content = get_partial_line_content(&line_type, line); - html.push_str(&line_content); - } else { - html.push_str(&get_heading_wrapper(&mut heading_stack, &line_type)); - html.push_str(&get_full_line_content(&line_type, line)); - } - current_line_type = Some(line_type); - }, - } - } - if let Some(line) = ¤t_line_type { - if is_block(line) { - html.push_str(get_line_closer(line)); - } - } - html.push_str(&close_heading_wrapper(&mut heading_stack)); - html -} - -fn is_block(line_type: &LineType) -> bool { - return match line_type { - LineType::PreformattedText | LineType::ListItem | LineType::Quote => true, - _ => false, - } -} - -fn get_partial_line_content(line_type: &LineType, line: &str) -> String { - let encoded_line = line.replace("<", "<").replace(">", ">"); - return match line_type { - LineType::ListItem => format!("<li>{}</li>", encoded_line[2..].trim()), - LineType::Quote => encoded_line[1..].trim().to_string(), - LineType::PreformattedText => format!("{}\n", encoded_line), - LineType::PreformattedToggle => encoded_line[3..].trim().to_string(), - _ => "".to_string(), - } -} - -fn get_full_line_content(line_type: &LineType, line: &str) -> String { - let encoded_line = line.replace("<", "<").replace(">", ">"); - match line_type { - LineType::Text => format!("<p>{}</p>\n", encoded_line.trim()), - LineType::Blank => "<br>\n".to_string(), - LineType::Link => { - let url = get_link_address(line); - if url.starts_with("gemini:") { - format!("<div><a href=\"{}\">{}</a></div>\n", url, get_link_content(line)) - } else { - format!("<div><a href=\"{}\">{}</a></div>\n", url.replace(".gmi", ".html"), get_link_content(line)) - } - }, - LineType::Heading1 => format!("<h1>{}</h1>\n", encoded_line[1..].trim()), - LineType::Heading2 => format!("<h2>{}</h2>\n", encoded_line[2..].trim()), - LineType::Heading3 => format!("<h3>{}</h3>\n", encoded_line[3..].trim()), - _ => "".to_string(), - } -} - -fn get_heading_wrapper(heading_stack: &mut Vec<u8>, line_type: &LineType) -> String { - let mut string = String::new(); - let current_heading: u8 = match line_type { - LineType::Heading1 => 1, - LineType::Heading2 => 2, - LineType::Heading3 => 3, - _ => 255 - }; - - if current_heading < 255 { - while let Some(open_heading) = heading_stack.pop() { - // You just encountered a more important heading. - // Put it back. Desist. - if open_heading < current_heading { - heading_stack.push(open_heading); - break; - } - - string.push_str("</div>"); - - if open_heading == current_heading { - break; - } - } - heading_stack.push(current_heading); - string.push_str(&format!("<div class=\"h{}\">", current_heading)); - } - - return string; -} - -fn close_heading_wrapper(heading_stack: &mut Vec<u8>) -> String { - let mut string = String::new(); - while let Some(_open_heading) = heading_stack.pop() { - string.push_str("</div>"); - } - return string; -} - -fn get_line_opener(line_type: &LineType, block_label: Option<&String>) -> String { - match line_type { - LineType::ListItem => "<ul>".to_string(), - LineType::Quote => "<blockquote>".to_string(), - LineType::PreformattedText => { - if let Some(label) = &block_label { - return format!("<pre role=\"img\" aria-label=\"{}\">", label); - } else { - return "<pre>".to_string(); - } - }, - _ => "".to_string(), - } -} - -fn get_line_closer(line_type: &LineType) -> &'static str { - match line_type { - LineType::ListItem => "</ul>\n", - LineType::Quote => "</blockquote>\n", - LineType::PreformattedText => "</pre>\n", - _ => "", - } -} - -fn get_link_content(line: &str) -> &str { - let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect(); - if components.len() > 1 { - return components[1].trim() - } - components[0].trim() -} - -fn get_link_address(line: &str) -> &str { - let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect(); - components[0].trim() -} - -fn identify_line(line: &str, is_preformatted: bool) -> LineType { - if line.starts_with("```") { - return LineType::PreformattedToggle; - } - if is_preformatted { - return LineType::PreformattedText; - } - if line.is_empty() { - return LineType::Blank; - } - if line.starts_with("=>") { - return LineType::Link; - } - if line.starts_with("* ") { - return LineType::ListItem; - } - if line.starts_with(">") { - return LineType::Quote; - } - if line.starts_with("###") { - return LineType::Heading3; - } - if line.starts_with("##") { - return LineType::Heading2; - } - if line.starts_with("#") { - return LineType::Heading1; - } - - LineType::Text -} - -#[derive(PartialEq, Eq)] -enum LineType { - Text, - Blank, - Link, - PreformattedToggle, - PreformattedText, - Heading1, - Heading2, - Heading3, - ListItem, - Quote -} diff --git a/src/generator/html.rs b/src/generator/html.rs index ab47b7a..7b36944 100644 --- a/src/generator/html.rs +++ b/src/generator/html.rs @@ -1,11 +1,16 @@ +use crate::template::{find, parse, TemplateContext}; use std::fs::write; use std::io::{Error, ErrorKind::Other, Result}; use std::path::PathBuf; -use crate::template::{find, parse, TemplateContext}; const FILENAME: &str = "index.html"; -pub fn generate(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, context: &TemplateContext) -> Result<()> { +pub fn generate( + _: &PathBuf, + template_directory: &PathBuf, + target: &PathBuf, + context: &TemplateContext, +) -> Result<()> { match find(template_directory, FILENAME) { Some(template) => { let parsed_template = parse(&template) @@ -13,7 +18,7 @@ pub fn generate(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, con let rendered_template = parsed_template.render(context)?; let location = target.join(FILENAME); write(location, rendered_template)?; - }, + } None => {} } Ok(()) diff --git a/src/generator/mod.rs b/src/generator/mod.rs index e967e41..293ad7d 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -1,29 +1,38 @@ -mod static_files; mod html; mod rss; +mod static_files; mod txt; -use std::io::Result; -use std::path::PathBuf; use crate::post::Post; use crate::template::TemplateContext; +use std::io::Result; +use std::path::PathBuf; -pub fn generate(static_directory: &PathBuf, template_directory: &PathBuf, output_directory: &PathBuf, posts: &Vec<Post>) -> Result<()> { +pub fn generate( + static_directory: &PathBuf, + template_directory: &PathBuf, + output_directory: &PathBuf, + posts: &Vec<Post>, +) -> Result<()> { let generators = available_generators(); let context = Post::to_template_context(&posts); for generator in generators { - generator(static_directory, template_directory, output_directory, &context)?; + generator( + static_directory, + template_directory, + output_directory, + &context, + )?; } Ok(()) } - fn available_generators() -> Vec<fn(&PathBuf, &PathBuf, &PathBuf, &TemplateContext) -> Result<()>> { vec![ static_files::generate, // These three are actually the same. Can generalize, don't know how in rust yet. html::generate, rss::generate, - txt::generate + txt::generate, ] } diff --git a/src/generator/rss.rs b/src/generator/rss.rs index 6a13bb8..9705f8e 100644 --- a/src/generator/rss.rs +++ b/src/generator/rss.rs @@ -1,11 +1,16 @@ +use crate::template::{find, parse, TemplateContext}; use std::fs::write; use std::io::{Error, ErrorKind::Other, Result}; use std::path::PathBuf; -use crate::template::{find, parse, TemplateContext}; const FILENAME: &str = "feed.xml"; -pub fn generate(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, context: &TemplateContext) -> Result<()> { +pub fn generate( + _: &PathBuf, + template_directory: &PathBuf, + target: &PathBuf, + context: &TemplateContext, +) -> Result<()> { match find(template_directory, FILENAME) { Some(template) => { let parsed_template = parse(&template) @@ -13,7 +18,7 @@ pub fn generate(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, con let rendered_template = parsed_template.render(context)?; let location = target.join(FILENAME); write(location, rendered_template)?; - }, + } None => {} } Ok(()) diff --git a/src/generator/static_files.rs b/src/generator/static_files.rs index 401eacf..8c55de3 100644 --- a/src/generator/static_files.rs +++ b/src/generator/static_files.rs @@ -1,11 +1,16 @@ -use std::io::Result; -use std::path::PathBuf; use crate::template::TemplateContext; use crate::utils::recursively_copy; +use std::io::Result; +use std::path::PathBuf; -pub fn generate(source: &PathBuf, _: &PathBuf, target: &PathBuf, _: &TemplateContext) -> Result<()> { +pub fn generate( + source: &PathBuf, + _: &PathBuf, + target: &PathBuf, + _: &TemplateContext, +) -> Result<()> { if source.exists() { - return recursively_copy(source, target) + return recursively_copy(source, target); } Ok(()) } diff --git a/src/generator/txt.rs b/src/generator/txt.rs index f505480..e146c15 100644 --- a/src/generator/txt.rs +++ b/src/generator/txt.rs @@ -1,11 +1,16 @@ +use crate::template::{find, parse, TemplateContext}; use std::fs::write; use std::io::{Error, ErrorKind::Other, Result}; use std::path::PathBuf; -use crate::template::{find, parse, TemplateContext}; const FILENAME: &str = "index.txt"; -pub fn generate(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, context: &TemplateContext) -> Result<()> { +pub fn generate( + _: &PathBuf, + template_directory: &PathBuf, + target: &PathBuf, + context: &TemplateContext, +) -> Result<()> { match find(template_directory, FILENAME) { Some(template) => { let parsed_template = parse(&template) @@ -13,7 +18,7 @@ pub fn generate(_: &PathBuf, template_directory: &PathBuf, target: &PathBuf, con let rendered_template = parsed_template.render(context)?; let location = target.join(FILENAME); write(location, rendered_template)?; - }, + } None => {} } Ok(()) diff --git a/src/main.rs b/src/main.rs index 535a2dd..6c529ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,19 @@ -mod configuration; +mod archiver; mod command; +mod configuration; mod constants; -mod gemini_parser; mod generator; -mod archiver; mod metadata; mod post; +mod remote; mod template; mod utils; -mod remote; -use std::iter::once; +use command::{available_commands, help::Help, Command}; +use configuration::Configuration; use std::env::args; use std::io::Result; -use command::{available_commands, Command, help::Help}; -use configuration::Configuration; +use std::iter::once; fn main() -> Result<()> { let result = run(); @@ -55,7 +54,7 @@ fn run() -> Result<()> { } } - return Ok(()) + return Ok(()); } } diff --git a/src/metadata.rs b/src/metadata.rs index b2f67c5..e016db6 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -1,16 +1,15 @@ +use serde::{Deserialize, Serialize}; use std::fs::File; -use std::path::PathBuf; use std::io::Read; +use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; -use time::{OffsetDateTime, format_description::well_known::Rfc2822}; -use serde::{Serialize, Deserialize}; -use serde_json; +use time::{format_description::well_known::Rfc2822, OffsetDateTime}; #[derive(Serialize, Deserialize)] pub struct Metadata { pub id: String, #[serde(alias = "createdOn")] - pub created_on: u64 + pub created_on: u64, } impl Metadata { @@ -24,20 +23,18 @@ impl Metadata { .unwrap_or_else(|_| 0); return Metadata { id: timestamp.to_string(), - created_on: timestamp - } + created_on: timestamp, + }; } } } pub fn created_on_utc(&self) -> Option<String> { - let date = OffsetDateTime::from_unix_timestamp_nanos( - (self.created_on * 1_000_000).into() - ).ok()?; + let date = + OffsetDateTime::from_unix_timestamp_nanos((self.created_on * 1_000_000).into()).ok()?; return date.format(&Rfc2822).ok(); } - fn read_metadata_file(file_path: &PathBuf) -> Option<Metadata> { let mut file = File::open(file_path).ok()?; let mut contents = String::new(); diff --git a/src/post.rs b/src/post.rs index 0250bff..afe6b77 100644 --- a/src/post.rs +++ b/src/post.rs @@ -1,35 +1,30 @@ -use std::collections::HashMap; use crate::metadata::Metadata; use crate::template::{TemplateContext, TemplateValue}; +use std::collections::HashMap; pub struct Post { pub metadata: Metadata, pub index: u8, pub html: String, - pub raw: String + pub raw: String, } impl Post { pub fn to_template_context(posts: &Vec<Post>) -> TemplateContext { let mut context = HashMap::new(); - let posts_collection = posts - .iter() - .map(|post| post.to_template_value()) - .collect(); + let posts_collection = posts.iter().map(|post| post.to_template_value()).collect(); context.insert( "has_posts".to_string(), - TemplateValue::Bool(posts.len() > 0) + TemplateValue::Bool(posts.len() > 0), ); context.insert( "posts_length".to_string(), - TemplateValue::Unsigned( - posts.len().try_into().unwrap() - ) + TemplateValue::Unsigned(posts.len().try_into().unwrap()), ); context.insert( "posts".to_string(), - TemplateValue::Collection(posts_collection) + TemplateValue::Collection(posts_collection), ); context @@ -39,46 +34,46 @@ impl Post { context.insert( "id".to_string(), - TemplateValue::String(format!("{}", self.metadata.id)) + TemplateValue::String(format!("{}", self.metadata.id)), ); context.insert( "created_on".to_string(), - TemplateValue::Unsigned(self.metadata.created_on) + TemplateValue::Unsigned(self.metadata.created_on), ); if let Some(created_on_utc) = self.metadata.created_on_utc() { context.insert( "created_on_utc".to_string(), - TemplateValue::String(created_on_utc) + TemplateValue::String(created_on_utc), ); } - context.insert( - "title".to_string(), - TemplateValue::String(self.title()) - ); + context.insert("title".to_string(), TemplateValue::String(self.title())); context.insert( "index".to_string(), - TemplateValue::Unsigned(self.index.into()) + TemplateValue::Unsigned(self.index.into()), ); context.insert( "html".to_string(), - TemplateValue::String(format!("{}", self.html)) + TemplateValue::String(format!("{}", self.html)), ); context.insert( "escaped_html".to_string(), - TemplateValue::String(format!("{}", self.escaped_html())) + TemplateValue::String(format!("{}", self.escaped_html())), ); context.insert( "raw".to_string(), - TemplateValue::String(format!("{}", self.raw)) + TemplateValue::String(format!("{}", self.raw)), ); context } fn title(&self) -> String { - self.raw.trim() - .split('\n').next().unwrap() + self.raw + .trim() + .split('\n') + .next() + .unwrap() .replace('#', "") .replace("&", "&") .trim() @@ -86,7 +81,8 @@ impl Post { } fn escaped_html(&self) -> String { - self.html.replace("&", "&") + self.html + .replace("&", "&") .replace("<", "<") .replace(">", ">") .replace("\"", """) diff --git a/src/remote/git.rs b/src/remote/git.rs index 66c5a89..a8a9010 100644 --- a/src/remote/git.rs +++ b/src/remote/git.rs @@ -18,15 +18,24 @@ impl super::Remote for Git { } fn sync_up(&self, remote: &str, directory: &PathBuf) -> Result<()> { - let timestamp = SystemTime::now().duration_since(UNIX_EPOCH) + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) .map_err(|_| Error::new(Other, "Invalid time"))? .as_millis(); let commands = vec![ format!("cd {} && git init -b main", directory.display()), format!("cd {} && git add .", directory.display()), - format!("cd {} && git commit --allow-empty -m blog-sync-up-{}", directory.display(), timestamp), - format!("cd {} && git push {} main --force", directory.display(), remote), + format!( + "cd {} && git commit --allow-empty -m blog-sync-up-{}", + directory.display(), + timestamp + ), + format!( + "cd {} && git push {} main --force", + directory.display(), + remote + ), ]; for command in commands { diff --git a/src/remote/mod.rs b/src/remote/mod.rs index 19514af..49bfeb0 100644 --- a/src/remote/mod.rs +++ b/src/remote/mod.rs @@ -26,8 +26,8 @@ pub fn remove(remote_config: &PathBuf) -> Result<()> { } pub fn sync_up(data_directory: &PathBuf, remote_config: &PathBuf) -> Result<()> { - let remote_address = read_remote(remote_config) - .ok_or_else(|| Error::new(Other, "No remote is configured"))?; + let remote_address = + read_remote(remote_config).ok_or_else(|| Error::new(Other, "No remote is configured"))?; create_dir_all(data_directory)?; let remotes = available_remotes(); for remote in remotes { @@ -35,12 +35,15 @@ pub fn sync_up(data_directory: &PathBuf, remote_config: &PathBuf) -> Result<()> return remote.sync_up(&remote_address, data_directory); } } - Err(Error::new(Other, "No valid strategies found for your configured remote.")) + Err(Error::new( + Other, + "No valid strategies found for your configured remote.", + )) } pub fn sync_down(data_directory: &PathBuf, remote_config: &PathBuf) -> Result<()> { - let remote_address = read_remote(remote_config) - .ok_or_else(|| Error::new(Other, "No remote is configured"))?; + let remote_address = + read_remote(remote_config).ok_or_else(|| Error::new(Other, "No remote is configured"))?; create_dir_all(data_directory)?; let remotes = available_remotes(); for remote in remotes { @@ -48,13 +51,14 @@ pub fn sync_down(data_directory: &PathBuf, remote_config: &PathBuf) -> Result<() return remote.sync_down(&remote_address, data_directory); } } - Err(Error::new(Other, "No valid strategies found for your configured remote.")) + Err(Error::new( + Other, + "No valid strategies found for your configured remote.", + )) } fn available_remotes() -> Vec<Box<dyn Remote>> { - vec![ - Box::new(Git::new()) - ] + vec![Box::new(Git::new())] } fn read_remote(file_path: &PathBuf) -> Option<String> { diff --git a/src/template.rs b/src/template.rs index 0213fc3..9bd8644 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,42 +1,58 @@ -use std::io::{Error, ErrorKind::Other, Result}; use std::collections::HashMap; use std::fs::File; -use std::path::PathBuf; use std::io::Read; +use std::io::{Error, ErrorKind::Other, Result}; +use std::path::Path; -const TXT_TEMPLATE: &'static str = include_str!("../templates/index.txt"); -const HTML_TEMPLATE: &'static str = include_str!("../templates/index.html"); -const GMI_TEMPLATE: &'static str = include_str!("../templates/index.gmi"); -const RSS_TEMPLATE: &'static str = include_str!("../templates/feed.xml"); +const TXT_TEMPLATE: &str = include_str!("../templates/index.txt"); +const HTML_TEMPLATE: &str = include_str!("../templates/index.html"); +const GMI_TEMPLATE: &str = include_str!("../templates/index.gmi"); +const RSS_TEMPLATE: &str = include_str!("../templates/feed.xml"); // Parse and Render pub enum Token { Text(String), - DisplayDirective { content: String }, - ConditionalDirective { condition: String, children: Vec<Token>}, - IteratorDirective { collection: String, member_label: String, children: Vec<Token> } + DisplayDirective { + content: String, + }, + ConditionalDirective { + condition: String, + children: Vec<Token>, + }, + IteratorDirective { + collection: String, + member_label: String, + children: Vec<Token>, + }, } impl std::fmt::Display for Token { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Token::Text(label) => write!(f, "Text {}", label), - Token::DisplayDirective{content} => write!(f, "DisplayDirective {}", content), - Token::ConditionalDirective{condition, children} => { + Token::DisplayDirective { content } => write!(f, "DisplayDirective {}", content), + Token::ConditionalDirective { + condition, + children, + } => { write!(f, "ConditionalDirective {} [[[\n", condition)?; for child in children { write!(f, "\t{}\n", child)?; } write!(f, "\n]]]") - }, - Token::IteratorDirective{collection, member_label, children} => { + } + Token::IteratorDirective { + collection, + member_label, + children, + } => { write!(f, "{} in {}\n", collection, member_label)?; for child in children { write!(f, "\t{}\n", child)?; } write!(f, "\n]]]") - }, + } } } } @@ -47,7 +63,7 @@ pub enum TemplateValue { Unsigned(u64), Bool(bool), Collection(Vec<TemplateContext>), - Context(TemplateContext) + Context(TemplateContext), } impl TemplateValue { @@ -56,7 +72,7 @@ impl TemplateValue { TemplateValue::String(string) => string.to_string(), TemplateValue::Unsigned(number) => format!("{}", number), TemplateValue::Bool(bool) => format!("{}", bool), - _ => "".to_string() + _ => "".to_string(), } } } @@ -72,15 +88,17 @@ impl TemplateContextGetter { fn recursively_get_value(context: &TemplateContext, path: &[&str]) -> Option<TemplateValue> { match context.get(path[0]) { - Some(TemplateValue::Context(next)) if path.len() > 1 => TemplateContextGetter::recursively_get_value(next, &path[1..]), + Some(TemplateValue::Context(next)) if path.len() > 1 => { + TemplateContextGetter::recursively_get_value(next, &path[1..]) + } Some(value) if path.len() == 1 => Some(value.clone()), - _ => None + _ => None, } } } pub struct ParsedTemplate { - pub tokens: Vec<Token> + pub tokens: Vec<Token>, } impl ParsedTemplate { @@ -94,11 +112,15 @@ impl ParsedTemplate { match token { Token::Text(contents) => rendered_template.push_str(&contents), Token::DisplayDirective { content } => { - let value = TemplateContextGetter::get(context, &content) - .ok_or_else(|| Error::new(Other, format!("{} is not a valid key", content)))?; + let value = TemplateContextGetter::get(context, &content).ok_or_else(|| { + Error::new(Other, format!("{} is not a valid key", content)) + })?; rendered_template.push_str(&value.render()); - }, - Token::ConditionalDirective { condition, children} => { + } + Token::ConditionalDirective { + condition, + children, + } => { let mut negator = false; let mut condition = condition.to_string(); if condition.starts_with('!') { @@ -106,22 +128,34 @@ impl ParsedTemplate { condition = condition[1..].to_string(); } - let value = TemplateContextGetter::get(context, &condition) - .ok_or_else(|| Error::new(Other, format!("{} is not a valid key", condition)))?; + let value = + TemplateContextGetter::get(context, &condition).ok_or_else(|| { + Error::new(Other, format!("{} is not a valid key", condition)) + })?; match value { TemplateValue::Bool(value) => { if negator ^ value { - rendered_template.push_str(&ParsedTemplate::render_tokens(children, context)?) + rendered_template + .push_str(&ParsedTemplate::render_tokens(children, context)?) } Ok(()) - }, - _ => Err(Error::new(Other, format!("{} is not a boolean value", condition))), + } + _ => Err(Error::new( + Other, + format!("{} is not a boolean value", condition), + )), }?; - }, - Token::IteratorDirective { collection, member_label, children } => { - let value = TemplateContextGetter::get(context, &collection) - .ok_or_else(|| Error::new(Other, format!("{} is not a valid key", collection)))?; + } + Token::IteratorDirective { + collection, + member_label, + children, + } => { + let value = + TemplateContextGetter::get(context, &collection).ok_or_else(|| { + Error::new(Other, format!("{} is not a valid key", collection)) + })?; match value { TemplateValue::Collection(collection) => { @@ -129,13 +163,19 @@ impl ParsedTemplate { let mut child_context = context.clone(); child_context.insert( member_label.to_string(), - TemplateValue::Context(member) + TemplateValue::Context(member), ); - rendered_template.push_str(&ParsedTemplate::render_tokens(&children, &child_context)?) + rendered_template.push_str(&ParsedTemplate::render_tokens( + &children, + &child_context, + )?) } Ok(()) - }, - _ => Err(Error::new(Other, format!("{} is not a collection", collection))), + } + _ => Err(Error::new( + Other, + format!("{} is not a collection", collection), + )), }?; } } @@ -147,16 +187,15 @@ impl ParsedTemplate { pub fn parse(template: &str) -> Option<ParsedTemplate> { let mut tokens = Vec::new(); tokenize(template, &mut tokens).ok()?; - Some(ParsedTemplate { - tokens - }) + Some(ParsedTemplate { tokens }) } fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { let mut remaining_template = template; while !remaining_template.is_empty() && remaining_template.contains("{{") { - let directive_start_index = remaining_template.find("{{") + let directive_start_index = remaining_template + .find("{{") .ok_or_else(|| Error::new(Other, "Was expecting at least one tag opener"))?; if directive_start_index > 0 { let text = remaining_template[..directive_start_index].to_string(); @@ -164,8 +203,10 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { } remaining_template = &remaining_template[directive_start_index..]; - let directive_end_index = remaining_template.find("}}") - .ok_or_else(|| Error::new(Other, "Was expecting }} after {{"))? + 2; + let directive_end_index = remaining_template + .find("}}") + .ok_or_else(|| Error::new(Other, "Was expecting }} after {{"))? + + 2; let directive = &remaining_template[..directive_end_index]; remaining_template = &remaining_template[directive_end_index..]; @@ -174,10 +215,10 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { // Simple Directives '=' => { let content = directive[3..directive.len() - 2].trim(); - tokens.push(Token::DisplayDirective{ - content: content.to_string() + tokens.push(Token::DisplayDirective { + content: content.to_string(), }); - }, + } // Block Directives '?' | '~' => { let content = directive[3..directive.len() - 2].trim(); @@ -189,11 +230,11 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { let directive_block = &remaining_template[..closing_block]; remaining_template = &remaining_template[closing_block + 5..]; tokenize(directive_block, &mut children)?; - tokens.push(Token::ConditionalDirective{ + tokens.push(Token::ConditionalDirective { condition: content.to_string(), - children + children, }); - }, + } '~' => { let parts: Vec<_> = content.splitn(2, ':').collect(); let closing_block = remaining_template.find("{{~}}").unwrap(); @@ -204,14 +245,14 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { tokens.push(Token::IteratorDirective { collection: parts[0].trim().to_string(), member_label: parts[1].trim().to_string(), - children + children, }); } - }, - _ => unreachable!() + } + _ => unreachable!(), } - }, - _ => unreachable!() + } + _ => unreachable!(), } } tokens.push(Token::Text(remaining_template.to_string())); @@ -220,11 +261,15 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { // File helpers. -pub fn find(template_directory: &PathBuf, filename: &str) -> Option<String> { +pub fn find(template_directory: &Path, filename: &str) -> Option<String> { let template_path = template_directory.join(filename); if template_path.exists() { let mut contents = String::new(); - if File::open(template_path).ok()?.read_to_string(&mut contents).is_ok() { + if File::open(template_path) + .ok()? + .read_to_string(&mut contents) + .is_ok() + { return Some(contents); } } @@ -237,6 +282,6 @@ fn find_default(filename: &str) -> Option<String> { "index.html" => Some(HTML_TEMPLATE.to_string()), "index.gmi" => Some(GMI_TEMPLATE.to_string()), "index.rss" => Some(RSS_TEMPLATE.to_string()), - &_ => None + &_ => None, } } diff --git a/src/utils.rs b/src/utils.rs index c9d8426..4522f4c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,8 +1,8 @@ -use std::io::Result; -use std::path::PathBuf; use std::fs::{copy, create_dir_all, read_dir}; +use std::io::Result; +use std::path::Path; -pub fn recursively_copy(source: &PathBuf, target: &PathBuf) -> Result<()> { +pub fn recursively_copy(source: &Path, target: &Path) -> Result<()> { let entries = read_dir(source)?; for entry in entries { let entry = entry?; |