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
use ::epub_builder;
use ::thiserror::Error;
use ::handlebars;
#[macro_use]
extern crate log;
use ::mdbook;
use ::semver;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
use mdbook::config::Config as MdConfig;
use mdbook::renderer::RenderContext;
use semver::{Version, VersionReq};
use std::fs::{create_dir_all, File};
use std::path::{Path, PathBuf};
mod config;
mod generator;
mod resources;
pub use crate::config::Config;
pub use crate::generator::Generator;
pub const DEFAULT_CSS: &str = include_str!("master.css");
#[derive(Error, Debug)]
pub enum Error {
#[error("Incompatible mdbook version got {0} expected {1}")]
IncompatibleVersion(String, String),
#[error("{0}")]
EpubDocCreate(String),
#[error("Could not parse the template")]
TemplateParse,
#[error("Content file was not found: \'{0}\'")]
ContentFileNotFound(String),
#[error("{0}")]
AssetFileNotFound(String),
#[error("Asset was not a file {0}")]
AssetFile(PathBuf),
#[error("Could not open css file {0}")]
CssOpen(PathBuf),
#[error("Unable to open template {0}")]
OpenTemplate(PathBuf),
#[error("Unable to parse render context")]
RenderContext,
#[error("Unable to open asset")]
AssetOpen,
#[error("Error reading stylesheet")]
StylesheetRead,
#[error("Epub check failed, ensure the epubcheck program is installed")]
EpubCheck,
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Book(#[from] mdbook::errors::Error),
#[error(transparent)]
Semver(#[from] semver::SemVerError),
#[error(transparent)]
SemverReqParse(#[from] semver::ReqParseError),
#[error(transparent)]
EpubBuilder(#[from] epub_builder::Error),
#[error(transparent)]
Render(#[from] handlebars::RenderError),
#[error(transparent)]
TomlDeser(#[from] toml::de::Error),
}
pub const MDBOOK_VERSION: &str = mdbook::MDBOOK_VERSION;
fn version_check(ctx: &RenderContext) -> Result<(), Error> {
let provided_version = Version::parse(&ctx.version)?;
let required_version = VersionReq::parse(&format!("~{}", MDBOOK_VERSION))?;
if !required_version.matches(&provided_version) {
Err(Error::IncompatibleVersion(
MDBOOK_VERSION.to_string(), ctx.version.clone()))
} else {
Ok(())
}
}
pub fn generate(ctx: &RenderContext) -> Result<(), Error> {
info!("Starting the EPUB generator");
version_check(ctx)?;
let outfile = output_filename(&ctx.destination, &ctx.config);
trace!("Output File: {}", outfile.display());
if !ctx.destination.exists() {
debug!(
"Creating destination directory ({})",
ctx.destination.display()
);
create_dir_all(&ctx.destination)?;
}
let f = File::create(&outfile)?;
Generator::new(ctx)?.generate(f)?;
Ok(())
}
pub fn output_filename(dest: &Path, config: &MdConfig) -> PathBuf {
match config.book.title {
Some(ref title) => dest.join(title).with_extension("epub"),
None => dest.join("book.epub"),
}
}