1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use std::{fmt, path::PathBuf};
use thiserror::Error;
use crate::config::File;
#[derive(Debug, Error, Clone, PartialEq)]
pub enum WordListGenerationError {
#[error("SRT file could not be parsed.")]
InvalidSRT,
#[error("The file `{0}` could not be found.")]
FileNotFound(PathBuf),
#[error("Could not determine the file's filetype. Please give this file a file extension Stork knows about, or disambiguate the file's filetype within your config.")]
CannotDetermineFiletype,
#[error("The selector `{0}` is not present in the HTML document.")]
SelectorNotPresent(String),
#[error("The web page could not be fetched")]
WebPageNotFetched,
#[error("When fetched, the web page returned a {0} status code.")]
WebPageErrorfulStatusCode(u16),
#[error("Content-Type is not present or invalid")]
UnknownContentType,
#[error("After parsing the document, there were no words found in the word list.")]
EmptyWordList,
#[error("Stork was not built with the `web-scraping` feature enabled.")]
FeatureNotAvailable,
}
fn pluralize_with_count(count: usize, singular: &str, plural: &str) -> String {
format!("{} {}", count, if count == 1 { singular } else { plural })
}
#[derive(Debug, Error)]
pub enum IndexGenerationError {
#[error("No files specified in config file")]
NoFilesSpecified,
#[error("All files failed to be indexed.\n{}", DocumentError::display_list(.0))]
AllDocumentErrors(Vec<DocumentError>),
#[allow(clippy::all)]
#[error(
"{} found while indexing files. If you want to fail silently and still build an index, remove `break_on_file_error` from your config.\n{}",
pluralize_with_count(.0.len(), "error", "errors"),
DocumentError::display_list(.0)
)]
PartialDocumentErrors(Vec<DocumentError>),
}
impl PartialEq for IndexGenerationError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::AllDocumentErrors(_), Self::AllDocumentErrors(_)) => true,
(Self::PartialDocumentErrors(_), Self::PartialDocumentErrors(_)) => true,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct DocumentError {
pub file: File,
pub word_list_generation_error: WordListGenerationError,
}
impl std::fmt::Display for DocumentError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"In file `{}`: {}",
self.file,
self.word_list_generation_error.to_string(),
)
}
}
impl DocumentError {
pub fn display_list(vec: &[DocumentError]) -> String {
format!(
"Warning: Stork couldn't include {} in the index because of the following errors:\n",
pluralize_with_count(vec.len(), "file", "files"),
) + &vec
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join("\n")
}
}
#[cfg(test)]
mod tests {
use crate::config::DataSource;
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_documenterrors_display() {
let computed = DocumentError {
file: File {
title: "My Test File".to_string(),
explicit_source: Some(DataSource::Contents("ignored".to_string())),
..Default::default()
},
word_list_generation_error: WordListGenerationError::FileNotFound(PathBuf::from(
"/test",
)),
}
.to_string();
let expected = "In file `My Test File`: The file `/test` could not be found.";
assert_eq!(computed, expected);
}
#[test]
fn test_documenterror_list_display() {
let computed = DocumentError::display_list(&[
DocumentError {
file: File {
title: "My Test File".to_string(),
explicit_source: Some(DataSource::Contents("ignored".to_string())),
..Default::default()
},
word_list_generation_error: WordListGenerationError::FileNotFound(PathBuf::from(
"/test",
)),
},
DocumentError {
file: File {
title: "My Test File 2".to_string(),
explicit_source: Some(DataSource::Contents("ignored 2".to_string())),
..Default::default()
},
word_list_generation_error: WordListGenerationError::FileNotFound(PathBuf::from(
"/test2",
)),
},
]);
let expected = "Warning: Stork couldn't include 2 files in the index because of the following errors:\nIn file `My Test File`: The file `/test` could not be found.\nIn file `My Test File 2`: The file `/test2` could not be found.";
assert_eq!(computed, expected);
}
}