aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Letan <contact@thomasletan.fr>2019-08-14 15:46:45 +0200
committerThomas Letan <contact@thomasletan.fr>2019-08-14 15:46:45 +0200
commit4a512ae35ce03d98c08fdf3f1531a438f99fb086 (patch)
tree5289ee92f0de31650d22de79aa4c1c74df9d5c98
parentrefactor: Introduce the [EpubWriter] trait (diff)
feature: Generate the epub archive
Previously, the content of the epub was generated in a dedicated build directory, and it was necessary to make the final step (generating the archive) manually. With this patch, the archive is generated, but no compression method is performed. We add a new dependency to the `zip-rs' crate, since the latter appears to be the go-to solution for generating zip archives.
-rw-r--r--Cargo.lock79
-rw-r--r--Cargo.toml1
-rw-r--r--src/epub.rs104
-rw-r--r--src/main.rs8
4 files changed, 184 insertions, 8 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0d86324..a50f628 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "adler32"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "aho-corasick"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -86,6 +91,24 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "bzip2"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "cc"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -101,6 +124,7 @@ dependencies = [
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.11.20 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "zip 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -134,6 +158,14 @@ dependencies = [
]
[[package]]
+name = "crc32fast"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "deunicode"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -216,6 +248,17 @@ version = "0.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "libflate"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "maplit"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -320,6 +363,11 @@ dependencies = [
]
[[package]]
+name = "podio"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -366,6 +414,11 @@ version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "rle-decode-fast"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "rustc-demangle"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -475,6 +528,11 @@ dependencies = [
]
[[package]]
+name = "take_mut"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "tera"
version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -676,7 +734,20 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "zip"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[metadata]
+"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
@@ -688,10 +759,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+"checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
+"checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f"
"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum deunicode 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
@@ -704,6 +778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b0f90c979adde96d19eb10eb6431ba0c441e2f9e9bdff868b2f6f5114ff519"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
+"checksum libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "45c97cf62125b79dcac52d506acdc4799f21a198597806947fd5f40dc7b93412"
"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
@@ -718,12 +793,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646"
"checksum pest_meta 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f249ea6de7c7b7aba92b4ff4376a994c6dbd98fd2166c89d5c4947397ecb574d"
+"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d8297cc20bbb6184f8b45ff61c8ee6a9ac56c156cec8e38c3e5084773c44ad"
"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f"
+"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
@@ -739,6 +816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum static_assertions 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4f8de36da215253eb5f24020bfaa0646613b48bf7ebe36cdfa37c3b3b33b241"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)" = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3"
+"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
"checksum tera 0.11.20 (registry+https://github.com/rust-lang/crates.io-index)" = "4b505279e19d8f7d24b1a9dc58327c9c36174b1a2c7ebdeac70792d017cb64f3"
"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
@@ -766,3 +844,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+"checksum zip 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c18fc320faf909036e46ac785ea827f72e485304877faf1a3a39538d3714dbc3"
diff --git a/Cargo.toml b/Cargo.toml
index fbad847..d05a914 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,6 +10,7 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
tera = "0.11"
+zip = "0.5"
[dependencies.ogmarkup]
git = "https://git.sr.ht/~lthms/ogmarkup/"
diff --git a/src/epub.rs b/src/epub.rs
index 15167c1..785f497 100644
--- a/src/epub.rs
+++ b/src/epub.rs
@@ -1,14 +1,21 @@
-use std::fs;
+use std::env::set_current_dir;
use std::fs::{create_dir, remove_dir_all, create_dir_all};
+use std::fs;
+use std::io::{Read, Write};
use std::path::{Path, PathBuf};
-use std::env::set_current_dir;
-use tera::{Tera, Context};
use serde_json::json;
+use tera::{Tera, Context};
+
use crate::error::{Raise, Error};
use crate::project::{Project, Chapter};
+use zip::write::FileOptions;
+use zip::ZipWriter;
+use std::fs::File;
+use std::collections::HashSet;
+
const EPUB_MIMETYPE: &'static str = "application/epub+zip";
pub trait EpubWriter {
@@ -31,9 +38,7 @@ pub trait EpubWriter {
dst : &PathBuf,
input : &str
) -> Result<(), Error> ;
-}
-impl EpubWriter {
fn create_mimetype(&mut self) -> Result<(), Error> {
self.write_str(&PathBuf::from("mimetype"), EPUB_MIMETYPE)
}
@@ -94,7 +99,7 @@ impl EpubWriter {
Ok(extension.into())
}
- pub fn generate(&mut self, project : &Project<String>, assets : &PathBuf) -> Result<(), Error> {
+ fn generate(&mut self, project : &Project<String>, assets : &PathBuf) -> Result<(), Error> {
let tera = compile_templates!(template_dir(assets)?.as_str());
@@ -243,3 +248,90 @@ impl EpubWriter for Fs {
Ok(())
}
}
+
+pub struct Zip {
+ output : ZipWriter<File>,
+ dirs : HashSet<PathBuf>,
+}
+
+impl Zip {
+ pub fn init() -> Result<Zip, Error> {
+ let file = File::create("Book.epub").or_raise("Could not create Book.epub")?;
+
+ Ok(Zip {
+ output : ZipWriter::new(file),
+ dirs : HashSet::new(),
+ })
+ }
+
+ fn create_parent(&mut self, dst : &PathBuf) -> Result<(), Error> {
+ if let Some(dir) = dst.parent() {
+ if self.dirs.contains(dir) {
+ self.output.add_directory_from_path(dir, FileOptions::default())
+ .or_raise(&format!("Could not create directory {:?}", dir))?;
+ self.dirs.insert(dir.to_path_buf());
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl EpubWriter for Zip {
+ fn write_template(
+ &mut self,
+ dst : &PathBuf,
+ tera : & Tera,
+ template : &str,
+ ctx : &Context,
+ ) -> Result<(), Error> {
+ self.create_parent(dst)?;
+
+ let content = tera.render(template, ctx)
+ .or_raise(&format!("cannot render {}", template))?;
+
+ self.output.start_file_from_path(dst, FileOptions::default())
+ .or_raise(&format!("Could not add file {:?} to archive", dst))?;
+
+ self.output.write_all(content.as_bytes())
+ .or_raise(&format!("Could not write {:?} content", dst))?;
+
+ Ok(())
+ }
+
+ fn write_str(
+ &mut self,
+ dst : &PathBuf,
+ input : &str
+ ) -> Result<(), Error> {
+ self.create_parent(dst)?;
+
+ self.output.start_file_from_path(dst, FileOptions::default())
+ .or_raise(&format!("Could not add file {:?} to archive", dst))?;
+
+ self.output.write_all(input.as_bytes())
+ .or_raise(&format!("Could not write {:?} content", dst))?;
+
+ Ok(())
+ }
+
+ fn write_file(
+ &mut self,
+ dst : &PathBuf,
+ src : &PathBuf,
+ ) -> Result<(), Error> {
+ let mut buffer = Vec::new();
+ let mut f = File::open(src).or_raise(&format!("Could not open {:?}", src))?;
+ f.read_to_end(&mut buffer).or_raise(&format!("Could not read {:?} content", src))?;
+
+ self.create_parent(dst)?;
+
+ self.output.start_file_from_path(dst, FileOptions::default())
+ .or_raise(&format!("Could not add file {:?} to archive", dst))?;
+
+ self.output.write_all(buffer.as_ref())
+ .or_raise(&format!("Could not write {:?} content", dst))?;
+
+ Ok(())
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 63f80c3..d95e119 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,6 +5,7 @@ extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate tera;
+extern crate zip;
use clap::{App, SubCommand};
@@ -24,7 +25,7 @@ use ogmarkup::typography::FRENCH;
use error::Error;
use project::Project;
-use epub::Fs;
+use epub::{Zip, Fs};
use epub::EpubWriter;
@@ -34,8 +35,11 @@ pub fn build(assets : &PathBuf) -> Result<(), Error> {
let project = Project::find_project()?
.load_and_render(&FRENCH)?;
+ let mut zip_writer = Zip::init()?;
+ zip_writer.generate(&project, assets)?;
+
let mut fs_writer = Fs::init()?;
- EpubWriter::generate(&mut fs_writer, &project, assets)?;
+ fs_writer.generate(&project, assets)?;
Ok(())
}