aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-01-05 00:38:55 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2025-01-05 00:38:55 +0100
commitd7fef30ac3f539975ef9edbba8e0af4a4e9ff3de (patch)
tree1e71dd131261a8f7a13d86d4dddd7d421e6a09f4 /src
parentd26464d12e41e8d53fca8d0e5f9cc6ac03e48f9a (diff)
Commit batch of lints to allow autofix
Diffstat (limited to 'src')
-rw-r--r--src/archiver/gemini.rs26
-rw-r--r--src/archiver/gopher.rs26
-rw-r--r--src/archiver/mod.rs87
-rw-r--r--src/archiver/raw.rs11
-rw-r--r--src/command/add.rs13
-rw-r--r--src/command/add_remote.rs15
-rw-r--r--src/command/generate.rs42
-rw-r--r--src/command/help.rs8
-rw-r--r--src/command/mod.rs30
-rw-r--r--src/command/publish.rs18
-rw-r--r--src/command/publish_archive.rs23
-rw-r--r--src/command/remove_remote.rs4
-rw-r--r--src/command/status/blog_status.rs8
-rw-r--r--src/command/status/configuration_status.rs19
-rw-r--r--src/command/status/mod.rs13
-rw-r--r--src/command/sync_down.rs16
-rw-r--r--src/command/sync_up.rs15
-rw-r--r--src/command/update.rs50
-rw-r--r--src/command/version.rs8
-rw-r--r--src/configuration.rs34
-rw-r--r--src/gemini_parser.rs225
-rw-r--r--src/generator/html.rs11
-rw-r--r--src/generator/mod.rs23
-rw-r--r--src/generator/rss.rs11
-rw-r--r--src/generator/static_files.rs13
-rw-r--r--src/generator/txt.rs11
-rw-r--r--src/main.rs15
-rw-r--r--src/metadata.rs19
-rw-r--r--src/post.rs46
-rw-r--r--src/remote/git.rs15
-rw-r--r--src/remote/mod.rs22
-rw-r--r--src/template.rs157
-rw-r--r--src/utils.rs6
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) = &current_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) = &current_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) = &current_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("<", "&lt;").replace(">", "&gt;");
- 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("<", "&lt;").replace(">", "&gt;");
- 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("&", "&amp;")
.trim()
@@ -86,7 +81,8 @@ impl Post {
}
fn escaped_html(&self) -> String {
- self.html.replace("&", "&amp;")
+ self.html
+ .replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace("\"", "&quot;")
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?;