aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-04-06 00:57:56 +0200
committerRuben Beltran del Rio <git@r.bdr.sh>2025-04-06 00:57:56 +0200
commitd0f582b98712d967b2f95d0405886d063bd89468 (patch)
treecc644c21278d336772557366bcdd3e46b22065db /src
parent8b3b94a38b443c50afc5b42cca45db7c18ce280d (diff)
Get stricter clippy
Diffstat (limited to 'src')
-rw-r--r--src/archiver/mod.rs98
-rw-r--r--src/command/add.rs2
-rw-r--r--src/command/add_remote.rs4
-rw-r--r--src/command/generate.rs24
-rw-r--r--src/command/help.rs2
-rw-r--r--src/command/remove_remote.rs2
-rw-r--r--src/command/status/blog_status.rs15
-rw-r--r--src/command/status/configuration_status.rs27
-rw-r--r--src/command/status/mod.rs4
-rw-r--r--src/command/sync_down.rs6
-rw-r--r--src/command/sync_up.rs6
-rw-r--r--src/command/update.rs8
-rw-r--r--src/command/version.rs2
-rw-r--r--src/configuration.rs80
-rw-r--r--src/main.rs2
-rw-r--r--src/metadata.rs3
-rw-r--r--src/post.rs7
-rw-r--r--src/template.rs78
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('&', "&amp;")
.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!(),
}
}
_ => {