diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-04-06 00:57:56 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-04-06 00:57:56 +0200 |
| commit | d0f582b98712d967b2f95d0405886d063bd89468 (patch) | |
| tree | cc644c21278d336772557366bcdd3e46b22065db /src | |
| parent | 8b3b94a38b443c50afc5b42cca45db7c18ce280d (diff) | |
Get stricter clippy
Diffstat (limited to 'src')
| -rw-r--r-- | src/archiver/mod.rs | 98 | ||||
| -rw-r--r-- | src/command/add.rs | 2 | ||||
| -rw-r--r-- | src/command/add_remote.rs | 4 | ||||
| -rw-r--r-- | src/command/generate.rs | 24 | ||||
| -rw-r--r-- | src/command/help.rs | 2 | ||||
| -rw-r--r-- | src/command/remove_remote.rs | 2 | ||||
| -rw-r--r-- | src/command/status/blog_status.rs | 15 | ||||
| -rw-r--r-- | src/command/status/configuration_status.rs | 27 | ||||
| -rw-r--r-- | src/command/status/mod.rs | 4 | ||||
| -rw-r--r-- | src/command/sync_down.rs | 6 | ||||
| -rw-r--r-- | src/command/sync_up.rs | 6 | ||||
| -rw-r--r-- | src/command/update.rs | 8 | ||||
| -rw-r--r-- | src/command/version.rs | 2 | ||||
| -rw-r--r-- | src/configuration.rs | 80 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/metadata.rs | 3 | ||||
| -rw-r--r-- | src/post.rs | 7 | ||||
| -rw-r--r-- | src/template.rs | 78 |
18 files changed, 218 insertions, 152 deletions
diff --git a/src/archiver/mod.rs b/src/archiver/mod.rs index 25c45a8..db3a841 100644 --- a/src/archiver/mod.rs +++ b/src/archiver/mod.rs @@ -5,7 +5,7 @@ mod raw; use crate::template::{Context, Value}; use std::collections::HashMap; use std::fs::read_dir; -use std::io::Result; +use std::io::{Error, ErrorKind, Result}; use std::path::{Path, PathBuf}; use time::{OffsetDateTime, format_description::FormatItem, macros::format_description}; @@ -19,7 +19,7 @@ struct ArchiveEntry { type Archiver = fn(&Path, &Path, &Path, &Context) -> Result<()>; impl ArchiveEntry { - pub fn to_template_context(archive_entries: &[ArchiveEntry]) -> Context { + pub fn to_template_context(archive_entries: &[ArchiveEntry]) -> Result<Context> { let mut context = HashMap::new(); let archive_entries_collection = archive_entries @@ -27,16 +27,20 @@ impl ArchiveEntry { .map(ArchiveEntry::to_template_value) .collect(); + let archive_length: u64 = archive_entries + .len() + .try_into() + .map_err(|_| Error::new(ErrorKind::Other, "Too many items in the archive."))?; context.insert( "archive_length".to_string(), - Value::Unsigned(archive_entries.len().try_into().unwrap()), + Value::Unsigned(archive_length), ); context.insert( "posts".to_string(), Value::Collection(archive_entries_collection), ); - context + Ok(context) } pub fn to_template_value(&self) -> Context { @@ -75,22 +79,19 @@ fn read_archive(archive_directory: &PathBuf) -> Vec<ArchiveEntry> { 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(), - }); - } + if let Some(extension) = candidate_path.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, } } } @@ -110,7 +111,7 @@ pub fn archive( ) -> Result<()> { let archivers = available_archivers(); let archive_entries = read_archive(archive_directory); - let context = ArchiveEntry::to_template_context(&archive_entries); + let context = ArchiveEntry::to_template_context(&archive_entries)?; for archiver in archivers { archiver( archive_directory, @@ -139,13 +140,15 @@ mod tests { #[test] fn test_creates_context_with_empty_archive_entries() { - let context = ArchiveEntry::to_template_context(&[]); - - assert_eq!(context["archive_length"], Value::Unsigned(0)); - if let Value::Collection(posts) = &context["posts"] { - assert!(posts.is_empty()); + if let Ok(context) = ArchiveEntry::to_template_context(&[]) { + assert_eq!(context.get("archive_length"), Some(&Value::Unsigned(0))); + if let Some(Value::Collection(posts)) = &context.get("posts") { + assert!(posts.is_empty()); + } else { + panic!("The posts context was not the right type."); + } } else { - panic!("The posts context was not the right type."); + panic!("Could not generate template context."); } } @@ -156,20 +159,22 @@ mod tests { slug: "the-archiving-shelves-with-a-spinning-lever-to-move-them".to_string(), }; - let context = ArchiveEntry::to_template_context(&[archive_entry]); - - assert_eq!(context["archive_length"], Value::Unsigned(1)); - if let Value::Collection(posts) = &context["posts"] { - if let Some(post) = posts.first() { - assert_eq!( - post["id"], - Value::String("you-know-what-is-cool".to_string()) - ); + if let Ok(context) = ArchiveEntry::to_template_context(&[archive_entry]) { + assert_eq!(context.get("archive_length"), Some(&Value::Unsigned(1))); + if let Some(Value::Collection(posts)) = &context.get("posts") { + if let Some(post) = posts.first() { + assert_eq!( + post["id"], + Value::String("you-know-what-is-cool".to_string()) + ); + } else { + panic!("The template context had no posts"); + } } else { - panic!("The template context had no posts"); + panic!("The posts context was not the right type."); } } else { - panic!("The posts context was not the right type."); + panic!("Could not generate context"); } } @@ -183,12 +188,14 @@ mod tests { let context = archive_entry.to_template_value(); assert_eq!( - context["id"], - Value::String("they-always-show-them-in-spy-films".to_string()) + context.get("id"), + Some(&Value::String( + "they-always-show-them-in-spy-films".to_string() + )) ); assert_eq!( - context["slug"], - Value::String("or-like-universities".to_string()) + context.get("slug"), + Some(&Value::String("or-like-universities".to_string())) ); assert!(!context.contains_key("title")); } @@ -202,14 +209,17 @@ mod tests { let context = archive_entry.to_template_value(); - assert_eq!(context["id"], Value::String("1736035200000".to_string())); assert_eq!( - context["slug"], - Value::String("need-a-warehouse".to_string()) + context.get("id"), + Some(&Value::String("1736035200000".to_string())) + ); + assert_eq!( + context.get("slug"), + Some(&Value::String("need-a-warehouse".to_string())) ); assert_eq!( - context["title"], - Value::String("2025-01-05 need a warehouse".to_string()) + context.get("title"), + Some(&Value::String("2025-01-05 need a warehouse".to_string())) ); } diff --git a/src/command/add.rs b/src/command/add.rs index 132b7cd..7079707 100644 --- a/src/command/add.rs +++ b/src/command/add.rs @@ -73,7 +73,7 @@ mod tests { // Create Test Files // Create configuration - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.posts_directory = posts_dir.clone(); // Let's ensure the initial state is OK diff --git a/src/command/add_remote.rs b/src/command/add_remote.rs index a40b184..aa3f745 100644 --- a/src/command/add_remote.rs +++ b/src/command/add_remote.rs @@ -61,7 +61,7 @@ mod tests { let remote_config = test_dir.join("blogremote"); assert!(!remote_config.exists()); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.config_directory = test_dir.clone(); configuration.remote_config = remote_config.clone(); add_remote @@ -74,7 +74,7 @@ mod tests { #[test] fn test_fails_if_no_remote_sent() { let add_remote = AddRemote::new(); - let configuration = Configuration::new(); + let configuration = Configuration::new().unwrap(); let result = add_remote.execute(None, &configuration, "add_remote"); assert!(result.is_err()); } diff --git a/src/command/generate.rs b/src/command/generate.rs index ac9849e..33ea6a4 100644 --- a/src/command/generate.rs +++ b/src/command/generate.rs @@ -21,9 +21,8 @@ impl Generate { for i in 0..max_posts { let post_path = posts_directory.join(i.to_string()); - match Generate::read_post(&post_path, i) { - Some(post) => posts.push(post), - None => continue, + if let Some(post) = Generate::read_post(&post_path, i) { + posts.push(post); } } @@ -34,16 +33,13 @@ impl Generate { let entries = read_dir(post_path).ok()?; for entry in entries.filter_map(Result::ok) { let entry_path = entry.path(); - match entry_path.extension() { - Some(extension) => { - if extension == "gmi" { - let mut file = File::open(entry_path).ok()?; - let mut contents = String::new(); - file.read_to_string(&mut contents).ok()?; - return Some(contents); - } + if let Some(extension) = entry_path.extension() { + if extension == "gmi" { + let mut file = File::open(entry_path).ok()?; + let mut contents = String::new(); + file.read_to_string(&mut contents).ok()?; + return Some(contents); } - None => continue, } } None @@ -190,7 +186,7 @@ mod tests { .write_all(&invalid_bytes) .expect("Could not write bad bytes to bad file."); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.archive_directory = archive_dir.clone(); configuration.static_directory = static_dir.clone(); configuration.templates_directory = template_dir.clone(); @@ -263,7 +259,7 @@ mod tests { "{ \"id\": \"1736045200000\", \"created_on\": 1736045200000 }", ); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.archive_directory = archive_dir.clone(); configuration.static_directory = static_dir.clone(); configuration.templates_directory = template_dir.clone(); diff --git a/src/command/help.rs b/src/command/help.rs index c018aa7..c29af39 100644 --- a/src/command/help.rs +++ b/src/command/help.rs @@ -50,7 +50,7 @@ mod tests { fn test_help_command() { let help = Help::new(); - let configuration = Configuration::new(); + let configuration = Configuration::new().unwrap(); help.execute(None, &configuration, "") .expect("Could not call help"); } diff --git a/src/command/remove_remote.rs b/src/command/remove_remote.rs index 0d274d7..910d089 100644 --- a/src/command/remove_remote.rs +++ b/src/command/remove_remote.rs @@ -51,7 +51,7 @@ mod tests { create_test_file(&remote_config, "boop"); assert!(remote_config.exists()); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.remote_config = remote_config.clone(); remove_remote .execute(None, &configuration, "") diff --git a/src/command/status/blog_status.rs b/src/command/status/blog_status.rs index 48f608a..3f42f32 100644 --- a/src/command/status/blog_status.rs +++ b/src/command/status/blog_status.rs @@ -1,19 +1,26 @@ use crate::configuration::Configuration; +use std::fmt::Write; use std::fs::read_dir; +use std::io::{Error, ErrorKind, Result}; use std::path::PathBuf; -pub fn status(configuration: &Configuration) -> String { +pub fn status(configuration: &Configuration) -> Result<String> { let mut status_message = String::new(); status_message.push_str("# Blog\n"); // Main Configuration Locations let blog_count = count_entries(&configuration.posts_directory); - status_message.push_str(&format!("Number of posts in blog: {blog_count}\n")); + writeln!(&mut status_message, "Number of posts in blog: {blog_count}") + .map_err(|_| Error::new(ErrorKind::Other, "Unable to write status"))?; let archive_count = count_entries(&configuration.archive_directory); - status_message.push_str(&format!("Number of posts in archive: {archive_count}\n")); - status_message + writeln!( + &mut status_message, + "Number of posts in archive: {archive_count}" + ) + .map_err(|_| Error::new(ErrorKind::Other, "Unable to write status"))?; + Ok(status_message) } fn count_entries(path: &PathBuf) -> String { diff --git a/src/command/status/configuration_status.rs b/src/command/status/configuration_status.rs index 96555c6..7babff8 100644 --- a/src/command/status/configuration_status.rs +++ b/src/command/status/configuration_status.rs @@ -1,8 +1,10 @@ use crate::configuration::Configuration; +use std::fmt::Write; use std::fs; +use std::io::{Error, ErrorKind, Result}; use std::path::PathBuf; -pub fn status(configuration: &Configuration) -> String { +pub fn status(configuration: &Configuration) -> Result<String> { let mut status_message = String::new(); status_message.push_str("# Configuration\n"); @@ -12,25 +14,28 @@ pub fn status(configuration: &Configuration) -> String { 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("Data", &configuration.data_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", + writeln!( + &mut status_message, + "Number of posts to keep: {}", configuration.max_posts - )); - status_message + ) + .map_err(|_| Error::new(ErrorKind::Other, "Unable to write status"))?; + Ok(status_message) } -fn get_directory_stats(label: &str, directory: &PathBuf) -> String { +fn get_directory_stats(label: &str, directory: &PathBuf) -> Result<String> { let mut status_message = String::new(); - status_message.push_str(&format!("{}: {}. ", label, directory.display())); + write!(&mut status_message, "{}: {}. ", label, directory.display()) + .map_err(|_| Error::new(ErrorKind::Other, "Unable to write status"))?; if directory.exists() { status_message.push_str("Exists "); if fs::read_dir(directory).is_ok() { @@ -42,5 +47,5 @@ fn get_directory_stats(label: &str, directory: &PathBuf) -> String { status_message.push_str("Does not exist.\n"); } - status_message + Ok(status_message) } diff --git a/src/command/status/mod.rs b/src/command/status/mod.rs index b92ef5f..3bad923 100644 --- a/src/command/status/mod.rs +++ b/src/command/status/mod.rs @@ -20,7 +20,7 @@ impl super::Command for Status { 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)); + println!("{}\n----\n", status_provider(configuration)?); } Ok(()) } @@ -38,6 +38,6 @@ impl super::Command for Status { } } -fn available_status_providers() -> Vec<fn(&Configuration) -> String> { +fn available_status_providers() -> Vec<fn(&Configuration) -> Result<String>> { vec![configuration_status::status, blog_status::status] } diff --git a/src/command/sync_down.rs b/src/command/sync_down.rs index bc9d983..a95dd1a 100644 --- a/src/command/sync_down.rs +++ b/src/command/sync_down.rs @@ -74,7 +74,7 @@ mod tests { assert!(!&local_dir.join("file1.txt").exists()); assert!(!&local_dir.join("file2.txt").exists()); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.data_directory = local_dir.clone(); configuration.remote_config = test_dir.join("remoteconfig"); @@ -107,7 +107,7 @@ mod tests { let test_dir = setup_test_dir(); create_test_file(&test_dir.join("remoteconfigdown"), "DO NOT WAAANT"); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.data_directory = test_dir.clone(); configuration.remote_config = test_dir.join("remoteconfig"); @@ -123,7 +123,7 @@ mod tests { let test_dir = setup_test_dir(); create_test_file(&test_dir.join("remoteconfigdown"), "DO NOT WAAANT"); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.data_directory = test_dir.clone(); configuration.remote_config = test_dir.join("remoteconfig"); diff --git a/src/command/sync_up.rs b/src/command/sync_up.rs index 5761071..57c4e1c 100644 --- a/src/command/sync_up.rs +++ b/src/command/sync_up.rs @@ -70,7 +70,7 @@ mod tests { let remote_dir_as_string = remote_dir.display().to_string(); create_test_file(&test_dir.join("remoteconfig"), &remote_dir_as_string); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.data_directory = local_dir.clone(); configuration.remote_config = test_dir.join("remoteconfig"); @@ -101,7 +101,7 @@ mod tests { let test_dir = setup_test_dir(); create_test_file(&test_dir.join("remoteconfig"), "DO NOT WAAANT"); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.data_directory = test_dir.clone(); configuration.remote_config = test_dir.join("remoteconfig"); @@ -117,7 +117,7 @@ mod tests { let test_dir = setup_test_dir(); create_test_file(&test_dir.join("remoteconfig"), "DO NOT WAAANT"); - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.data_directory = test_dir.clone(); configuration.remote_config = test_dir.join("remoteconfig"); diff --git a/src/command/update.rs b/src/command/update.rs index e415872..1da6198 100644 --- a/src/command/update.rs +++ b/src/command/update.rs @@ -135,7 +135,7 @@ mod tests { let archive_dir = test_dir.join("archive"); // Create configuration - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.posts_directory = posts_dir.clone(); configuration.archive_directory = archive_dir.clone(); @@ -245,7 +245,7 @@ mod tests { create_dir_all(&nested_dir).expect("Could not create nested dir."); // Create configuration - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.posts_directory = posts_dir.clone(); configuration.archive_directory = archive_dir.clone(); @@ -271,7 +271,7 @@ mod tests { let archive_dir = test_dir.join("archive"); // Create configuration - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.posts_directory = posts_dir.clone(); configuration.archive_directory = archive_dir.clone(); @@ -293,7 +293,7 @@ mod tests { let archive_dir = test_dir.join("archive"); // Create configuration - let mut configuration = Configuration::new(); + let mut configuration = Configuration::new().unwrap(); configuration.posts_directory = posts_dir.clone(); configuration.archive_directory = archive_dir.clone(); diff --git a/src/command/version.rs b/src/command/version.rs index 53328e6..12f2a85 100644 --- a/src/command/version.rs +++ b/src/command/version.rs @@ -44,7 +44,7 @@ mod tests { fn test_version_command() { let version = Version::new(); - let configuration = Configuration::new(); + let configuration = Configuration::new().unwrap(); version .execute(None, &configuration, "") .expect("Could not call version"); diff --git a/src/configuration.rs b/src/configuration.rs index afee277..b598764 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,4 +1,5 @@ use std::env; +use std::io::{Error, ErrorKind, Result}; use std::path::PathBuf; pub struct Configuration { @@ -25,21 +26,21 @@ pub struct Configuration { } impl Configuration { - pub fn new() -> Self { + pub fn new() -> Result<Self> { let config_directory = Configuration::directory( "BLOG_CONFIG_DIRECTORY", "XDG_CONFIG_HOME", ".config", "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"); + Configuration::directory("BLOG_OUTPUT_DIRECTORY", "XDG_CACHE_HOME", ".cache", "blog")?; let max_posts: u8 = env::var("BLOG_MAX_POSTS") .ok() @@ -56,7 +57,7 @@ impl Configuration { let blog_output_directory = output_directory.join("blog"); let archive_output_directory = output_directory.join("archive"); - Configuration { + Ok(Configuration { config_directory, data_directory, output_directory, @@ -68,7 +69,7 @@ impl Configuration { templates_directory, blog_output_directory, archive_output_directory, - } + }) } fn directory( @@ -76,19 +77,22 @@ impl Configuration { default_value: &str, home_fallback: &str, path: &str, - ) -> PathBuf { + ) -> Result<PathBuf> { match env::var(user_override) { - Ok(directory) => PathBuf::from(directory), + Ok(directory) => Ok(PathBuf::from(directory).join(path)), Err(_) => match env::var(default_value) { - Ok(directory) => PathBuf::from(directory), - Err(_) => env::var("HOME") - .map_or_else( - |_| panic!("Could not find required directory, {user_override} or {default_value} should be set and readable"), - |directory| PathBuf::from(directory).join(home_fallback) - ) + Ok(directory) => Ok(PathBuf::from(directory).join(path)), + Err(_) => match env::var("HOME") { + Ok(directory) => Ok(PathBuf::from(directory).join(home_fallback).join(path)), + Err(_) => Err(Error::new( + ErrorKind::NotFound, + format!( + "Could not find required directory, {user_override} or {default_value} should be set and readable" + ), + )), + }, }, } - .join(path) } } @@ -102,6 +106,8 @@ mod tests { #[test] fn test_reads_configuration_from_configuration_variable_if_set() { let test_dir = setup_test_dir(); + + // SAFETY: Run only in single-threaded mode unsafe { env::set_var("TEST_BLOG_CONFIG_DIRECTORY", &test_dir); } @@ -111,15 +117,19 @@ mod tests { "XDG_CONFIG_HOME", ".config", "beepboop", - ); + ) + .expect("Could not get config directory"); assert_eq!(config_directory, test_dir.join("beepboop")); + cleanup_test_dir(&test_dir); } #[test] fn test_reads_configuration_from_default_location_if_configuration_variable_not_set() { let test_dir = setup_test_dir(); + + // SAFETY: Run only in single-threaded mode unsafe { env::set_var("TEST_XDG_CONFIG_HOME", &test_dir); } @@ -129,9 +139,11 @@ mod tests { "TEST_XDG_CONFIG_HOME", ".config", "beepboop", - ); + ) + .expect("Could not get config directory"); assert_eq!(config_directory, test_dir.join("beepboop")); + cleanup_test_dir(&test_dir); } @@ -144,23 +156,51 @@ mod tests { "UNDEFINED_FAKE_XDG_CONFIG_HOME", ".config", "beepboop", - ); + ) + .expect("Could not get config directory"); assert_eq!(config_directory, path.join(".config/beepboop")); } #[test] + fn test_fails_configuration_if_no_variable_is_set() { + let original_home = env::var("HOME").unwrap(); + + // SAFETY: Run only in single-threaded mode + unsafe { + env::remove_var("HOME"); + } + + assert!( + Configuration::directory( + "UNDEFINED_BLOG_CONFIG_DIRECTORY", + "UNDEFINED_FAKE_XDG_CONFIG_HOME", + ".config", + "beepboop", + ) + .is_err() + ); + + // SAFETY: Run only in single-threaded mode + unsafe { + env::set_var("HOME", original_home); + } + } + + #[test] fn test_sets_correct_configuration_directories() { - let default_configuration = Configuration::new(); + let default_configuration = Configuration::new().unwrap(); let test_dir = setup_test_dir(); + + // SAFETY: Run only in single-threaded mode unsafe { env::set_var("BLOG_CONFIG_DIRECTORY", test_dir.join("config")); env::set_var("BLOG_DATA_DIRECTORY", test_dir.join("data")); env::set_var("BLOG_OUTPUT_DIRECTORY", test_dir.join("output")); env::set_var("BLOG_MAX_POSTS", "99"); } - let override_configuration = Configuration::new(); + let override_configuration = Configuration::new().unwrap(); // Ensure our overrides were applied diff --git a/src/main.rs b/src/main.rs index 45ebe7b..9245dcc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ fn main() -> Result<()> { } fn run() -> Result<()> { - let configuration = Configuration::new(); + let configuration = Configuration::new()?; let commands = available_commands(); let arguments: Vec<String> = args().collect(); diff --git a/src/metadata.rs b/src/metadata.rs index 8eff5cb..95ba1eb 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -24,8 +24,9 @@ impl Metadata { } else { let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).map_or_else( |_| 0, - |duration| u64::try_from(duration.as_millis()).expect("Timestamp is too big!"), + |duration| u64::try_from(duration.as_millis()).unwrap_or(0), ); + Metadata { id: timestamp.to_string(), created_on: timestamp, diff --git a/src/post.rs b/src/post.rs index 97c49f1..20322b4 100644 --- a/src/post.rs +++ b/src/post.rs @@ -16,9 +16,12 @@ impl Post { let posts_collection = posts.iter().map(Post::to_template_value).collect(); context.insert("has_posts".to_string(), Value::Bool(!posts.is_empty())); + + // If you really reach over 18 quintillion posts, I guess you can send + // me a bug-request via e-mail. context.insert( "posts_length".to_string(), - Value::Unsigned(posts.len().try_into().unwrap()), + Value::Unsigned(posts.len().try_into().unwrap_or(u64::MAX)), ); context.insert("posts".to_string(), Value::Collection(posts_collection)); @@ -55,7 +58,7 @@ impl Post { self.raw .lines() .next() - .unwrap() + .unwrap_or("") .replace('#', "") .replace('&', "&") .trim() diff --git a/src/template.rs b/src/template.rs index 2e4c8a6..8e61978 100644 --- a/src/template.rs +++ b/src/template.rs @@ -89,9 +89,11 @@ impl ContextGetter { } fn recursively_get_value(context: &Context, path: &[&str]) -> Option<Value> { - match context.get(path[0]) { + let next_path = path.first()?.to_owned(); + match context.get(next_path) { Some(Value::Context(next)) if path.len() > 1 => { - ContextGetter::recursively_get_value(next, &path[1..]) + let remainder = &path.get(1..)?.to_owned(); + ContextGetter::recursively_get_value(next, remainder) } Some(value) if path.len() == 1 => Some(value.clone()), _ => None, @@ -207,7 +209,7 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { let directive = &remaining_template[..directive_end_index]; remaining_template = &remaining_template[directive_end_index..]; - let directive_type = directive.chars().nth(2).unwrap(); + let directive_type = directive.chars().nth(2).unwrap_or(' '); match directive_type { // Simple Directives '=' => { @@ -221,42 +223,44 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) -> Result<()> { let content = directive[3..directive.len() - 2].trim(); let mut children = Vec::new(); - match directive_type { - '?' => { - let closing_block = remaining_template.find("{{?}}").ok_or_else(|| { - Error::new( - Other, - "Could not find closing tag, expecting {{?}}, found end-of-file", - ) - })?; - let directive_block = &remaining_template[..closing_block]; - remaining_template = &remaining_template[closing_block + 5..]; - tokenize(directive_block, &mut children)?; - tokens.push(Token::ConditionalDirective { - condition: content.to_string(), - children, - }); - } - '~' => { - let parts: Vec<_> = content.splitn(2, ':').collect(); - let closing_block = remaining_template.find("{{~}}").ok_or_else(|| { - Error::new( - Other, - "Could not find closing tag, expecting {{?}}, found end-of-file", - ) - })?; - let directive_block = &remaining_template[..closing_block]; - remaining_template = &remaining_template[closing_block + 5..]; - tokenize(directive_block, &mut children)?; - if parts.len() == 2 { - tokens.push(Token::IteratorDirective { - collection: parts[0].trim().to_string(), - member_label: parts[1].trim().to_string(), - children, - }); + if directive_type == '?' { + let closing_block = remaining_template.find("{{?}}").ok_or_else(|| { + Error::new( + Other, + "Could not find closing tag, expecting {{?}}, found end-of-file", + ) + })?; + let directive_block = &remaining_template[..closing_block]; + remaining_template = &remaining_template[closing_block + 5..]; + tokenize(directive_block, &mut children)?; + tokens.push(Token::ConditionalDirective { + condition: content.to_string(), + children, + }); + } else if directive_type == '~' { + let parts: Vec<_> = content.splitn(2, ':').collect(); + let closing_block = remaining_template.find("{{~}}").ok_or_else(|| { + Error::new( + Other, + "Could not find closing tag, expecting {{?}}, found end-of-file", + ) + })?; + let directive_block = &remaining_template[..closing_block]; + remaining_template = &remaining_template[closing_block + 5..]; + tokenize(directive_block, &mut children)?; + if parts.len() == 2 { + if let Some(first_part) = parts.first() { + if let Some(second_part) = parts.get(1) { + let collection = first_part.trim().to_string(); + let member_label = second_part.trim().to_string(); + tokens.push(Token::IteratorDirective { + collection, + member_label, + children, + }); + } } } - _ => unreachable!(), } } _ => { |