aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2024-03-09 15:34:57 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2024-03-09 15:34:57 +0100
commit50f53dc480fda8b3daab7a34454c2dd9f3f5f991 (patch)
tree2205be7a9c806ce59c851de9b50b9e18f973008d /src
parent172f4c8807d44ebe38c7f227b7fdc2d6a9dbe323 (diff)
Improve the error handlingrust
Diffstat (limited to 'src')
-rw-r--r--src/archiver/gemini.rs7
-rw-r--r--src/archiver/gopher.rs7
-rw-r--r--src/command/add_remote.rs5
-rw-r--r--src/command/publish.rs9
-rw-r--r--src/command/publish_archive.rs9
-rw-r--r--src/command/sync_down.rs9
-rw-r--r--src/command/sync_up.rs12
-rw-r--r--src/command/update.rs3
-rw-r--r--src/generator/html.rs7
-rw-r--r--src/generator/rss.rs7
-rw-r--r--src/generator/txt.rs7
-rw-r--r--src/main.rs16
-rw-r--r--src/remote/git.rs14
-rw-r--r--src/remote/mod.rs4
-rw-r--r--src/template.rs62
15 files changed, 115 insertions, 63 deletions
diff --git a/src/archiver/gemini.rs b/src/archiver/gemini.rs
index 8d56305..3b04bcf 100644
--- a/src/archiver/gemini.rs
+++ b/src/archiver/gemini.rs
@@ -1,5 +1,5 @@
use std::fs::write;
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use std::path::PathBuf;
use crate::template::{find, parse, TemplateContext};
@@ -8,8 +8,9 @@ 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 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)?;
},
diff --git a/src/archiver/gopher.rs b/src/archiver/gopher.rs
index 820e4d1..28f4f46 100644
--- a/src/archiver/gopher.rs
+++ b/src/archiver/gopher.rs
@@ -1,5 +1,5 @@
use std::fs::write;
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use std::path::PathBuf;
use crate::template::{find, parse, TemplateContext};
@@ -8,8 +8,9 @@ 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 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)?;
},
diff --git a/src/command/add_remote.rs b/src/command/add_remote.rs
index 040e572..e9157f3 100644
--- a/src/command/add_remote.rs
+++ b/src/command/add_remote.rs
@@ -1,4 +1,4 @@
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use crate::configuration::Configuration;
use crate::remote::add;
@@ -16,7 +16,8 @@ impl super::Command for AddRemote {
}
fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
- let input = input.expect("You must provide a location for the remote.");
+ 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)
}
diff --git a/src/command/publish.rs b/src/command/publish.rs
index 207b45d..34ca0d2 100644
--- a/src/command/publish.rs
+++ b/src/command/publish.rs
@@ -1,4 +1,4 @@
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use crate::configuration::Configuration;
use std::process::{Command, Stdio};
@@ -19,14 +19,15 @@ impl super::Command for Publish {
fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
- let input = input.expect("You must provide a location to publish the blog");
+ let input = input
+ .ok_or_else(|| Error::new(Other, "You must provide a location to publish the blog"))?;
Command::new(COMMAND)
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
- .expect("Publishing requires rsync");
+ .map_err(|_| Error::new(Other, "Publishing requires rsync"))?;
Command::new(COMMAND)
@@ -36,7 +37,7 @@ impl super::Command for Publish {
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
- .expect("Publishing requires rsync");
+ .map_err(|_| Error::new(Other, "Rsync failed to publish."))?;
return Ok(())
}
diff --git a/src/command/publish_archive.rs b/src/command/publish_archive.rs
index 075421f..c727c16 100644
--- a/src/command/publish_archive.rs
+++ b/src/command/publish_archive.rs
@@ -1,4 +1,4 @@
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use crate::configuration::Configuration;
use std::process::{Command, Stdio};
@@ -19,14 +19,15 @@ impl super::Command for PublishArchive {
fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
- let input = input.expect("You must provide a location to publish the archive");
+ let input = input
+ .ok_or_else(|| Error::new(Other, "You must provide a location to publish the archive"))?;
Command::new(COMMAND)
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
- .expect("Publishing requires rsync");
+ .map_err(|_| Error::new(Other, "Publishing requires rsync"))?;
Command::new(COMMAND)
@@ -36,7 +37,7 @@ impl super::Command for PublishArchive {
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
- .expect("Publishing requires rsync");
+ .map_err(|_| Error::new(Other, "Rsync failed to publish."))?;
return Ok(())
}
diff --git a/src/command/sync_down.rs b/src/command/sync_down.rs
index bba34b2..eb8e57a 100644
--- a/src/command/sync_down.rs
+++ b/src/command/sync_down.rs
@@ -16,8 +16,13 @@ impl super::Command for SyncDown {
}
fn execute(&self, _: Option<&String>, configuration: &Configuration, command: &String) -> Result<()> {
- if command == self.command() {
- return sync_down(&configuration.data_directory, &configuration.remote_config);
+ match sync_down(&configuration.data_directory, &configuration.remote_config) {
+ Ok(_) => {}
+ Err(e) => {
+ if command == self.command() {
+ return Err(e)
+ }
+ }
}
return Ok(())
}
diff --git a/src/command/sync_up.rs b/src/command/sync_up.rs
index a5d2a4c..c44e0b0 100644
--- a/src/command/sync_up.rs
+++ b/src/command/sync_up.rs
@@ -15,8 +15,16 @@ impl super::Command for SyncUp {
vec![]
}
- fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
- sync_up(&configuration.data_directory, &configuration.remote_config)
+ fn execute(&self, _: Option<&String>, configuration: &Configuration, command: &String) -> Result<()> {
+ match sync_up(&configuration.data_directory, &configuration.remote_config) {
+ Ok(_) => {}
+ Err(e) => {
+ if command == self.command() {
+ return Err(e)
+ }
+ }
+ }
+ return Ok(())
}
fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> {
diff --git a/src/command/update.rs b/src/command/update.rs
index 67cc462..8a3d6de 100644
--- a/src/command/update.rs
+++ b/src/command/update.rs
@@ -55,7 +55,8 @@ impl super::Command for Update {
}
fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
- let input = input.expect("You must provide a path to a post");
+ 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"));
diff --git a/src/generator/html.rs b/src/generator/html.rs
index b7ddd45..ab47b7a 100644
--- a/src/generator/html.rs
+++ b/src/generator/html.rs
@@ -1,5 +1,5 @@
use std::fs::write;
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use std::path::PathBuf;
use crate::template::{find, parse, TemplateContext};
@@ -8,8 +8,9 @@ const FILENAME: &str = "index.html";
pub fn generate(_: &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 parsed_template = parse(&template)
+ .ok_or_else(|| Error::new(Other, "Unable to parse HTML template"))?;
+ let rendered_template = parsed_template.render(context)?;
let location = target.join(FILENAME);
write(location, rendered_template)?;
},
diff --git a/src/generator/rss.rs b/src/generator/rss.rs
index 1aac73d..6a13bb8 100644
--- a/src/generator/rss.rs
+++ b/src/generator/rss.rs
@@ -1,5 +1,5 @@
use std::fs::write;
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use std::path::PathBuf;
use crate::template::{find, parse, TemplateContext};
@@ -8,8 +8,9 @@ const FILENAME: &str = "feed.xml";
pub fn generate(_: &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 parsed_template = parse(&template)
+ .ok_or_else(|| Error::new(Other, "Unable to parse RSS template"))?;
+ let rendered_template = parsed_template.render(context)?;
let location = target.join(FILENAME);
write(location, rendered_template)?;
},
diff --git a/src/generator/txt.rs b/src/generator/txt.rs
index ae260fe..f505480 100644
--- a/src/generator/txt.rs
+++ b/src/generator/txt.rs
@@ -1,5 +1,5 @@
use std::fs::write;
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use std::path::PathBuf;
use crate::template::{find, parse, TemplateContext};
@@ -8,8 +8,9 @@ const FILENAME: &str = "index.txt";
pub fn generate(_: &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 parsed_template = parse(&template)
+ .ok_or_else(|| Error::new(Other, "Unable to parse TXT template"))?;
+ let rendered_template = parsed_template.render(context)?;
let location = target.join(FILENAME);
write(location, rendered_template)?;
},
diff --git a/src/main.rs b/src/main.rs
index 8867dc0..a5c2cf6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,6 +18,22 @@ use command::{available_commands, Command, help::Help};
use configuration::Configuration;
fn main() -> Result<()> {
+ let result = run();
+
+ if cfg!(debug_assertions) {
+ result
+ } else {
+ match result {
+ Ok(_) => Ok(()),
+ Err(e) => {
+ eprintln!("Error: {}", e);
+ std::process::exit(1);
+ }
+ }
+ }
+}
+
+fn run() -> Result<()> {
let configuration = Configuration::new();
let commands = available_commands();
let arguments: Vec<String> = args().collect();
diff --git a/src/remote/git.rs b/src/remote/git.rs
index a4c1c28..66c5a89 100644
--- a/src/remote/git.rs
+++ b/src/remote/git.rs
@@ -1,6 +1,6 @@
-use std::io::Result;
+use std::io::{Error, ErrorKind::Other, Result};
use std::path::PathBuf;
-use std::process::Command;
+use std::process::{Command, Stdio};
use std::time::{SystemTime, UNIX_EPOCH};
pub struct Git;
@@ -19,7 +19,7 @@ impl super::Remote for Git {
fn sync_up(&self, remote: &str, directory: &PathBuf) -> Result<()> {
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)
- .expect("Invalid time")
+ .map_err(|_| Error::new(Other, "Invalid time"))?
.as_millis();
let commands = vec![
@@ -33,8 +33,10 @@ impl super::Remote for Git {
Command::new("sh")
.arg("-c")
.arg(&command)
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
.status()
- .expect("Failed while performing sync up with git");
+ .map_err(|_| Error::new(Other, "Failed while performing sync up with git"))?;
}
Ok(())
@@ -52,8 +54,10 @@ impl super::Remote for Git {
Command::new("sh")
.arg("-c")
.arg(&command)
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
.status()
- .expect("Failed while performing sync down with git");
+ .map_err(|_| Error::new(Other, "Failed while performing sync down with git"))?;
}
Ok(())
}
diff --git a/src/remote/mod.rs b/src/remote/mod.rs
index de90ef5..19514af 100644
--- a/src/remote/mod.rs
+++ b/src/remote/mod.rs
@@ -27,7 +27,7 @@ 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)
- .expect("No remote is configured");
+ .ok_or_else(|| Error::new(Other, "No remote is configured"))?;
create_dir_all(data_directory)?;
let remotes = available_remotes();
for remote in remotes {
@@ -40,7 +40,7 @@ pub fn sync_up(data_directory: &PathBuf, remote_config: &PathBuf) -> Result<()>
pub fn sync_down(data_directory: &PathBuf, remote_config: &PathBuf) -> Result<()> {
let remote_address = read_remote(remote_config)
- .expect("No remote is configured");
+ .ok_or_else(|| Error::new(Other, "No remote is configured"))?;
create_dir_all(data_directory)?;
let remotes = available_remotes();
for remote in remotes {
diff --git a/src/template.rs b/src/template.rs
index 0332506..0213fc3 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -1,3 +1,4 @@
+use std::io::{Error, ErrorKind::Other, Result};
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
@@ -83,20 +84,19 @@ pub struct ParsedTemplate {
}
impl ParsedTemplate {
- pub fn render(&self, context: &TemplateContext) -> String {
+ pub fn render(&self, context: &TemplateContext) -> Result<String> {
ParsedTemplate::render_tokens(&self.tokens, context)
}
- pub fn render_tokens(tokens: &Vec<Token>, context: &TemplateContext) -> String {
+ pub fn render_tokens(tokens: &Vec<Token>, context: &TemplateContext) -> Result<String> {
let mut rendered_template: String = String::new();
for token in tokens {
match token {
Token::Text(contents) => rendered_template.push_str(&contents),
Token::DisplayDirective { content } => {
- match TemplateContextGetter::get(context, &content) {
- Some(value) => rendered_template.push_str(&value.render()),
- None => panic!("{} 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} => {
let mut negator = false;
@@ -105,50 +105,59 @@ impl ParsedTemplate {
negator = true;
condition = condition[1..].to_string();
}
- match TemplateContextGetter::get(context, &condition) {
- Some(TemplateValue::Bool(value)) => {
+
+ 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(())
},
- _ => panic!("{} is not a boolean value", condition)
- }
+ _ => Err(Error::new(Other, format!("{} is not a boolean value", condition))),
+ }?;
},
Token::IteratorDirective { collection, member_label, children } => {
- match TemplateContextGetter::get(context, &collection) {
- Some(TemplateValue::Collection(collection)) => {
+ let value = TemplateContextGetter::get(context, &collection)
+ .ok_or_else(|| Error::new(Other, format!("{} is not a valid key", collection)))?;
+
+ match value {
+ TemplateValue::Collection(collection) => {
for member in collection {
let mut child_context = context.clone();
child_context.insert(
member_label.to_string(),
TemplateValue::Context(member)
);
- rendered_template.push_str(&ParsedTemplate::render_tokens(&children, &child_context))
+ rendered_template.push_str(&ParsedTemplate::render_tokens(&children, &child_context)?)
}
+ Ok(())
},
- _ => panic!("{} is not a collection", collection)
- }
+ _ => Err(Error::new(Other, format!("{} is not a collection", collection))),
+ }?;
}
}
}
- rendered_template
+ Ok(rendered_template)
}
}
-pub fn parse(template: &str) -> ParsedTemplate {
+pub fn parse(template: &str) -> Option<ParsedTemplate> {
let mut tokens = Vec::new();
- tokenize(template, &mut tokens);
- ParsedTemplate {
+ tokenize(template, &mut tokens).ok()?;
+ Some(ParsedTemplate {
tokens
- }
+ })
}
-fn tokenize(template: &str, tokens: &mut Vec<Token>) {
+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("{{")
- .expect("Was expecting at least one tag opener");
+ .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();
tokens.push(Token::Text(text.to_string()));
@@ -156,7 +165,7 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) {
remaining_template = &remaining_template[directive_start_index..];
let directive_end_index = remaining_template.find("}}")
- .expect("Was expecting }} after {{") + 2;
+ .ok_or_else(|| Error::new(Other, "Was expecting }} after {{"))? + 2;
let directive = &remaining_template[..directive_end_index];
remaining_template = &remaining_template[directive_end_index..];
@@ -179,7 +188,7 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) {
let closing_block = remaining_template.find("{{?}}").unwrap();
let directive_block = &remaining_template[..closing_block];
remaining_template = &remaining_template[closing_block + 5..];
- tokenize(directive_block, &mut children);
+ tokenize(directive_block, &mut children)?;
tokens.push(Token::ConditionalDirective{
condition: content.to_string(),
children
@@ -190,7 +199,7 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) {
let closing_block = remaining_template.find("{{~}}").unwrap();
let directive_block = &remaining_template[..closing_block];
remaining_template = &remaining_template[closing_block + 5..];
- tokenize(directive_block, &mut children);
+ tokenize(directive_block, &mut children)?;
if parts.len() == 2 {
tokens.push(Token::IteratorDirective {
collection: parts[0].trim().to_string(),
@@ -206,6 +215,7 @@ fn tokenize(template: &str, tokens: &mut Vec<Token>) {
}
}
tokens.push(Token::Text(remaining_template.to_string()));
+ Ok(())
}
// File helpers.