diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2024-03-08 23:38:23 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2024-03-08 23:38:23 +0100 |
| commit | 6352ebb0eb4cb83240c6d4998e0ef1375b041191 (patch) | |
| tree | 3ade08c77c8ab403d3196f80fad5ed3034c3035b /src/archiver | |
| parent | 60307a9a3a39dccf652c9d9b4348e44db1e67627 (diff) | |
Generate and archive blog, allow publishing
Diffstat (limited to 'src/archiver')
| -rw-r--r-- | src/archiver/gemini.rs | 19 | ||||
| -rw-r--r-- | src/archiver/gemini.txt | 0 | ||||
| -rw-r--r-- | src/archiver/gopher.rs | 19 | ||||
| -rw-r--r-- | src/archiver/gopher.txt | 0 | ||||
| -rw-r--r-- | src/archiver/mod.rs | 130 | ||||
| -rw-r--r-- | src/archiver/raw.rs | 11 |
6 files changed, 179 insertions, 0 deletions
diff --git a/src/archiver/gemini.rs b/src/archiver/gemini.rs new file mode 100644 index 0000000..8d56305 --- /dev/null +++ b/src/archiver/gemini.rs @@ -0,0 +1,19 @@ +use std::fs::write; +use std::io::Result; +use std::path::PathBuf; +use crate::template::{find, parse, TemplateContext}; + +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); + let rendered_template = parsed_template.render(context); + let location = target.join(FILENAME); + write(location, rendered_template)?; + }, + None => {} + } + Ok(()) +} diff --git a/src/archiver/gemini.txt b/src/archiver/gemini.txt deleted file mode 100644 index e69de29..0000000 --- a/src/archiver/gemini.txt +++ /dev/null diff --git a/src/archiver/gopher.rs b/src/archiver/gopher.rs new file mode 100644 index 0000000..820e4d1 --- /dev/null +++ b/src/archiver/gopher.rs @@ -0,0 +1,19 @@ +use std::fs::write; +use std::io::Result; +use std::path::PathBuf; +use crate::template::{find, parse, TemplateContext}; + +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); + let rendered_template = parsed_template.render(context); + let location = target.join(FILENAME); + write(location, rendered_template)?; + }, + None => {} + } + Ok(()) +} diff --git a/src/archiver/gopher.txt b/src/archiver/gopher.txt deleted file mode 100644 index e69de29..0000000 --- a/src/archiver/gopher.txt +++ /dev/null diff --git a/src/archiver/mod.rs b/src/archiver/mod.rs index e69de29..6f0c284 100644 --- a/src/archiver/mod.rs +++ b/src/archiver/mod.rs @@ -0,0 +1,130 @@ +mod raw; +mod gemini; +mod gopher; + +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}; + +const DATE_FORMAT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day]"); + +struct ArchiveEntry { + id: String, + slug: String +} + +impl ArchiveEntry { + pub fn to_template_context(archive_entries: &Vec<ArchiveEntry>) -> TemplateContext { + let mut context = HashMap::new(); + + let archive_entries_collection = archive_entries + .iter() + .map(|archive_entry| archive_entry.to_template_value()) + .collect(); + + context.insert( + "archive_length".to_string(), + TemplateValue::Unsigned( + archive_entries.len().try_into().unwrap() + ) + ); + context.insert( + "posts".to_string(), + TemplateValue::Collection(archive_entries_collection) + ); + + context + } + + pub fn to_template_value(&self) -> TemplateContext { + let mut context = HashMap::new(); + + context.insert( + "id".to_string(), + TemplateValue::String(self.id.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 + } + + fn title(&self) -> Option<String> { + let date = OffsetDateTime::from_unix_timestamp_nanos( + (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)) + } +} + +fn read_archive(archive_directory: &PathBuf) -> Vec<ArchiveEntry> { + let mut archive_entries = Vec::new(); + 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(); + if let Ok(entry_type) = entry.file_type() { + if entry_type.is_dir() { + if let Ok(candidates) = read_dir(&entry_path) { + for candidate in candidates.filter_map(Result::ok) { + let candidate_path = candidate.path(); + match candidate_path.extension() { + 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()) { + archive_entries.push(ArchiveEntry { + id: post_id.to_string(), + slug: slug.to_string() + }) + } + } + } + }, + _ => continue + } + } + } + } + } + } + } + + 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<()> { + 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)?; + } + return Ok(()) +} + +fn available_archivers() -> Vec<fn(&PathBuf, &PathBuf, &PathBuf, &TemplateContext) -> Result<()>> { + vec![ + raw::archive, + gemini::archive, + gopher::archive + ] +} diff --git a/src/archiver/raw.rs b/src/archiver/raw.rs new file mode 100644 index 0000000..5099f2b --- /dev/null +++ b/src/archiver/raw.rs @@ -0,0 +1,11 @@ +use std::io::Result; +use std::path::PathBuf; +use crate::template::TemplateContext; +use crate::utils::recursively_copy; + +pub fn archive(archive_directory: &PathBuf, _: &PathBuf, target: &PathBuf, _: &TemplateContext) -> Result<()> { + if archive_directory.exists() { + return recursively_copy(archive_directory, target); + } + Ok(()) +} |