Skip to content

Commit

Permalink
Pass result to error code
Browse files Browse the repository at this point in the history
  • Loading branch information
arranf committed Feb 22, 2019
1 parent 743edac commit fb4468c
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 15 deletions.
37 changes: 24 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ extern crate serde_derive;
mod config;
mod constants;
mod file_location;
mod operation_result;
mod page_index;
mod operation_result;
mod program_error;

use std::fs;
use std::env;
use std::path::{Path};

use crate::operation_result::*;
use crate::program_error::*;
use crate::page_index::*;
use crate::config::*;
use crate::file_location::*;
Expand All @@ -24,21 +26,29 @@ use toml::Value;
use walkdir::{DirEntry, WalkDir};
use yaml_rust::{YamlLoader};

fn main() -> Result<(), std::io::Error> {

fn main() -> Result<(), ProgramError> {
let args: Vec<String> = env::args().collect();
let config = Config::new(&args);

println!("Scanning {0}", &config.scan_path);
let index = traverse_files(&Path::new(&config.scan_path));
let index = serde_json::to_string(&index).expect("Unable to serialize page index");
let error_count: usize = index.iter().filter(|e| e.is_err()).count();
let index: Vec<PageIndex> = index.into_iter().filter_map(|a| a.ok()).collect();
let index = serde_json::to_string(&index)?;

println!("Writing index to {0}", &config.index_path);
fs::create_dir_all(Path::new(&config.index_path).with_file_name(constants::EMPTY_STRING)).expect("Error writing index");
fs::create_dir_all(Path::new(&config.index_path).with_file_name(constants::EMPTY_STRING))?;

fs::write(config.index_path, index)
fs::write(config.index_path, index)?;
if error_count > 0 {
Err(ProgramError::MetaError(MetaError::new(error_count, "Failed to process all content files")))
} else {
Ok(())
}
}

fn traverse_files(content_dir_path: &Path) -> Vec<PageIndex> {
fn traverse_files(content_dir_path: &Path) -> Vec<Result<PageIndex, OperationResult>> {
let mut index = Vec::new();
for entry in WalkDir::new(content_dir_path)
.into_iter()
Expand All @@ -48,12 +58,13 @@ fn traverse_files(content_dir_path: &Path) -> Vec<PageIndex> {
if file_location.is_err() {
continue;
}

match process_file(&file_location.unwrap()) {
Ok(page) => index.push(page),
Err(OperationResult::Parse(ref err)) => println!("{}", err),
Err(OperationResult::Io(ref err)) => println!("{}", err),
_ => ()
let process_result = process_file(&file_location.unwrap());
match process_result {
Err(OperationResult::Skip(ref err)) => println!("{}", err), // Skips don't need to be handled
Err(OperationResult::Path(ref err)) => { println!("{}", err); index.push(process_result); },
Err(OperationResult::Parse(ref err)) => { println!("{}", err); index.push(process_result); },
Err(OperationResult::Io(ref err)) => { println!("{}", err); index.push(process_result); },
Ok(_) => index.push(process_result)
}
} else if let Some(io_error) = entry.unwrap_err().into_io_error() {
println!("Failed {}", io_error);
Expand Down Expand Up @@ -151,7 +162,7 @@ fn process_yaml_front_matter(contents: &str, file_location: &FileLocation) -> Re
return Err(OperationResult::Parse(ParseError::new(&file_location.absolute_path, "Could not split on YAML fence.")))
}

let front_matter = split_content[length - 2].trim();
let front_matter = split_content[1].trim();
let front_matter = YamlLoader::load_from_str(front_matter)
.map_err(|_| ParseError::new(&file_location.absolute_path, "Failed to get front matter."))?;
let front_matter = front_matter.first()
Expand Down
4 changes: 2 additions & 2 deletions src/operation_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct Skip {

impl fmt::Display for Skip {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Skiping {}. {}", self.directory, self.reason)
write!(f, "Skipping {}. {}", self.directory, self.reason)
}
}

Expand Down Expand Up @@ -77,7 +77,7 @@ pub struct PathError {

impl fmt::Display for PathError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Skiping {}. {}", self.directory, self.reason)
write!(f, "Skipping {}. {}", self.directory, self.reason)
}
}

Expand Down
92 changes: 92 additions & 0 deletions src/program_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::io;
use std::error;
use std::fmt;

#[derive(Debug)]
pub struct MetaError {
reason: String,
count: usize
}

impl fmt::Display for MetaError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Program Error {}: {}", self.reason, self.count)
}
}

impl error::Error for MetaError {
fn description(&self) -> &str {
&self.reason
}

fn cause(&self) -> Option<&error::Error> {
None
}
}

impl MetaError {
pub fn new (count: usize, reason: &str) -> Self {
Self {
count: count,
reason: reason.to_owned(),
}
}
}

#[derive(Debug)]
pub enum ProgramError {
IoError(io::Error),
MetaError(MetaError),
SerializationError(serde_json::error::Error)
}

impl From<io::Error> for ProgramError {
fn from(err: io::Error) -> Self {
ProgramError::IoError(err)
}
}

impl From<MetaError> for ProgramError {
fn from(err: MetaError) -> Self {
ProgramError::MetaError(err)
}
}

impl From<serde_json::error::Error> for ProgramError {
fn from(err: serde_json::error::Error) -> Self {
ProgramError::SerializationError(err)
}
}

impl fmt::Display for ProgramError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ProgramError::IoError(ref err) => write!(f, "IO error: {}", err),
ProgramError::MetaError(ref err) => write!(f, "Serialization error: {}", err),
ProgramError::SerializationError(ref err) => write!(f, "Serialization error: {}", err),
}
}
}

impl error::Error for ProgramError {
fn description(&self) -> &str {
// Both underlying errors already impl `Error`, so we defer to their
// implementations.
match *self {
ProgramError::IoError(ref err) => err.description(),
ProgramError::MetaError(ref err) => err.description(),
ProgramError::SerializationError(ref err) => err.description(),
}
}

fn cause(&self) -> Option<&error::Error> {
match *self {
// N.B. Both of these implicitly cast `err` from their concrete
// types to a trait object `&Error`. This works because both error
// types implement `Error`.
ProgramError::IoError(ref err) => Some(err),
ProgramError::MetaError(ref err) => Some(err),
ProgramError::SerializationError(ref err) => Some(err)
}
}
}

0 comments on commit fb4468c

Please sign in to comment.