catch up with changes in master

This commit is contained in:
Gambhiro 2017-01-19 17:08:07 +00:00
parent ca718b3d78
commit c2ff0c6b15
64 changed files with 362 additions and 231 deletions

View File

@ -28,11 +28,12 @@ glob = "0.2"
log = "0.3" log = "0.3"
env_logger = "0.3" env_logger = "0.3"
toml = { version = "0.2", features = ["serde"] } toml = { version = "0.2", features = ["serde"] }
open = "1.1"
phf = "0.7" phf = "0.7"
includedir = "0.2" includedir = "0.2"
# Watch feature # Watch feature
notify = { version = "2.5.5", optional = true } notify = { version = "3.0", optional = true }
time = { version = "0.1.34", optional = true } time = { version = "0.1.34", optional = true }
crossbeam = { version = "0.2.8", optional = true } crossbeam = { version = "0.2.8", optional = true }

View File

@ -21,7 +21,7 @@
</tr> </tr>
</table> </table>
mdBook is a utility to create modern online books from markdown files. mdBook is a utility to create modern online books from Markdown files.
**This project is still evolving.** **This project is still evolving.**
See [#90](https://github.com/azerupi/mdBook/issues/90) See [#90](https://github.com/azerupi/mdBook/issues/90)
@ -29,7 +29,7 @@ See [#90](https://github.com/azerupi/mdBook/issues/90)
## What does it look like? ## What does it look like?
The [**Documentation**](http://azerupi.github.io/mdBook/) for mdBook has been written in markdown and is using mdBook to generate the online book-like website you can read. The documentation uses the latest version on github and showcases the available features. The [**Documentation**](http://azerupi.github.io/mdBook/) for mdBook has been written in Markdown and is using mdBook to generate the online book-like website you can read. The documentation uses the latest version on GitHub and showcases the available features.
## Installation ## Installation
@ -47,12 +47,12 @@ There are multiple ways to install mdBook.
This will download and compile mdBook for you, the only thing left to do is to add the Cargo bin directory to your `PATH`. This will download and compile mdBook for you, the only thing left to do is to add the Cargo bin directory to your `PATH`.
3. **From Git** 3. **From Git**
The version published to Crates.io will ever so slightly be behind the version hosted here on Github. If you need the latest version you can build the git version of mdBook yourself. Cargo makes this ***super easy***! The version published to crates.io will ever so slightly be behind the version hosted here on GitHub. If you need the latest version you can build the git version of mdBook yourself. Cargo makes this ***super easy***!
``` ```
cargo install --git https://github.com/azerupi/mdBook.git cargo install --git https://github.com/azerupi/mdBook.git
``` ```
Again, make sure to add the Cargo bin directory to your `PATH` Again, make sure to add the Cargo bin directory to your `PATH`.
4. **For Contributions** 4. **For Contributions**
If you want to contribute to mdBook you will have to clone the repository on your local machine: If you want to contribute to mdBook you will have to clone the repository on your local machine:
@ -74,7 +74,7 @@ There are multiple ways to install mdBook.
mdBook will primaraly be used as a command line tool, even though it exposes all its functionality as a Rust crate for integration in other projects. mdBook will primaraly be used as a command line tool, even though it exposes all its functionality as a Rust crate for integration in other projects.
Here are the main commands you will want to run, for a more exhaustive explanation, check out the [documentation](http://azerupi.github.io/mdBook/). Here are the main commands you will want to run. For a more exhaustive explanation, check out the [documentation](http://azerupi.github.io/mdBook/).
- `mdbook init` - `mdbook init`
@ -106,7 +106,7 @@ Here are the main commands you will want to run, for a more exhaustive explanati
### As a library ### As a library
Aside from the command line interface, this crate can also be used as a library. This means that you could integrate it in an existing project, like a web-app for example. Since the command line interface is just a wrapper around the library functionality, when you use this crate as a library you have full access to all the functionality of the command line interface with and easy to use API and more! Aside from the command line interface, this crate can also be used as a library. This means that you could integrate it in an existing project, like a web-app for example. Since the command line interface is just a wrapper around the library functionality, when you use this crate as a library you have full access to all the functionality of the command line interface with an easy to use API and more!
See the [Documentation](http://azerupi.github.io/mdBook/lib/lib.html) and the [API docs](http://azerupi.github.io/mdBook/mdbook/index.html) for more information. See the [Documentation](http://azerupi.github.io/mdBook/lib/lib.html) and the [API docs](http://azerupi.github.io/mdBook/mdbook/index.html) for more information.
@ -123,4 +123,4 @@ You can pick any issue you want to work on. Usually it's a good idea to ask if s
## License ## License
All the code is released under the ***Mozilla Public License v2.0***, for more information take a look at the [LICENSE](LICENSE) file All the code is released under the ***Mozilla Public License v2.0***, for more information take a look at the [LICENSE](LICENSE) file.

View File

@ -21,6 +21,15 @@ current working directory.
mdbook build path/to/book mdbook build path/to/book
``` ```
#### --open
When you use the `--open` (`-o`) option, mdbook will open the rendered book in
your default web browser after building it.
#### --dest-dir
The `--dest-dir` (`-d`) option allows you to change the output directory for your book.
------------------- -------------------
***note:*** *make sure to run the build command in the root directory and not in the source directory* ***note:*** *make sure to run the build command in the root directory and not in the source directory*

View File

@ -22,7 +22,7 @@ configuration files, etc.
- The `book` directory is where your book is rendered. All the output is ready to be uploaded - The `book` directory is where your book is rendered. All the output is ready to be uploaded
to a server to be seen by your audience. to a server to be seen by your audience.
- The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](../format/summary.html). - The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](format/summary.html).
#### Tip & Trick: Hidden Feature #### Tip & Trick: Hidden Feature
When a `SUMMARY.md` file already exists, the `init` command will first parse it and generate the missing files according to the paths used in the `SUMMARY.md`. This allows you to think and create the whole structure of your book and then let mdBook generate it for you. When a `SUMMARY.md` file already exists, the `init` command will first parse it and generate the missing files according to the paths used in the `SUMMARY.md`. This allows you to think and create the whole structure of your book and then let mdBook generate it for you.

View File

@ -26,8 +26,15 @@ mdbook server path/to/book -p 8000 -i 127.0.0.1 -a 192.168.1.100
If you were to want live reloading for this you would need to proxy the websocket calls through nginx as well from `192.168.1.100:<WS_PORT>` to `127.0.0.1:<WS_PORT>`. The `-w` flag allows for the websocket port to be configured. If you were to want live reloading for this you would need to proxy the websocket calls through nginx as well from `192.168.1.100:<WS_PORT>` to `127.0.0.1:<WS_PORT>`. The `-w` flag allows for the websocket port to be configured.
#### --open
When you use the `--open` (`-o`) option, mdbook will open the book in your
your default web browser after starting the server.
#### --dest-dir
The `--dest-dir` (`-d`) option allows you to change the output directory for your book.
----- -----
***note:*** *the `serve` command has not gotten a lot of testing yet, there could be some rough edges. If you discover a problem, please report it [on Github](https://github.com/azerupi/mdBook/issues)* ***note:*** *the `serve` command has not gotten a lot of testing yet, there could be some rough edges. If you discover a problem, please report it [on Github](https://github.com/azerupi/mdBook/issues)*
***note***:

View File

@ -12,6 +12,14 @@ current working directory.
mdbook watch path/to/book mdbook watch path/to/book
``` ```
#### --open
When you use the `--open` (`-o`) option, mdbook will open the rendered book in
your default web browser.
#### --dest-dir
The `--dest-dir` (`-d`) option allows you to change the output directory for your book.
----- -----

View File

@ -20,8 +20,9 @@ Here is a list of the properties that are exposed:
- ***language*** Language of the book in the form `en`. To use in <code class="language-html">\<html lang="{{ language }}"></code> for example. - ***language*** Language of the book in the form `en`. To use in <code class="language-html">\<html lang="{{ language }}"></code> for example.
At the moment it is hardcoded. At the moment it is hardcoded.
- ***title*** Title of the book, as specified in `book.toml` - ***title*** Title of the book, as specified in `book.toml`
- ***path*** Relative path to the original markdown file from the source directory - ***path*** Relative path to the original markdown file from the source directory
- ***chapter_title*** Title of the current chapter, as listed in `SUMMARY.md`
- ***content*** This is the rendered markdown. - ***content*** This is the rendered markdown.
- ***path_to_root*** This is a path containing exclusively `../`'s that points to the root of the book from the current file. - ***path_to_root*** This is a path containing exclusively `../`'s that points to the root of the book from the current file.
Since the original directory structure is maintained, it is useful to prepend relative links with this `path_to_root`. Since the original directory structure is maintained, it is useful to prepend relative links with this `path_to_root`.

View File

Before

Width:  |  Height:  |  Size: 348 KiB

After

Width:  |  Height:  |  Size: 348 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

2
data/book-init/book.toml Normal file
View File

@ -0,0 +1,2 @@
title = "An Empty Canvas"
author = "The Author"

View File

@ -0,0 +1,8 @@
# Title
[Introduction](introduction.md)
- [First Chapter](first-chapter.md)
- [Second Chapter]()
[Glossary](glossary.md)

View File

@ -0,0 +1,8 @@
# First Chapter
> first cicada &ndash;
> for a quick song sighted
> on the post
>
> *Issa, 1816*

View File

@ -0,0 +1,7 @@
# Glossary
**ci·ca·da** (sĭ-kādə, -kä-) *n. pl.* ci·ca·das or ci·ca·dae (-dē)
Any of various insects chiefly of the family Cicadidae, having a broad head,
membranous wings, and in the male a pair of resonating organs that produce a
characteristic high-pitched, droning sound.

View File

@ -0,0 +1 @@
# Introduction

View File

@ -5,6 +5,7 @@ extern crate clap;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate env_logger; extern crate env_logger;
extern crate open;
// Dependencies for the Watch feature // Dependencies for the Watch feature
#[cfg(feature = "watch")] #[cfg(feature = "watch")]
@ -23,7 +24,9 @@ extern crate staticfile;
extern crate ws; extern crate ws;
use std::env; use std::env;
use std::fs;
use std::error::Error; use std::error::Error;
use std::ffi::OsStr;
use std::io::{self, Write, ErrorKind}; use std::io::{self, Write, ErrorKind};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
@ -34,6 +37,8 @@ use clap::{App, ArgMatches, SubCommand, AppSettings};
#[cfg(feature = "watch")] #[cfg(feature = "watch")]
use notify::Watcher; use notify::Watcher;
#[cfg(feature = "watch")] #[cfg(feature = "watch")]
use std::time::Duration;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use mdbook::MDBook; use mdbook::MDBook;
@ -57,22 +62,28 @@ fn main() {
.subcommand(SubCommand::with_name("init") .subcommand(SubCommand::with_name("init")
.about("Create boilerplate structure and files in the directory") .about("Create boilerplate structure and files in the directory")
// the {n} denotes a newline which will properly aligned in all help messages // the {n} denotes a newline which will properly aligned in all help messages
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'") .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'")
.arg_from_usage("--copy-assets 'Copies the default assets (css, layout template, etc.) into your project folder'") .arg_from_usage("--copy-assets 'Copies the default assets (css, layout template, etc.) into your project folder'")
.arg_from_usage("--force 'skip confirmation prompts'")) .arg_from_usage("--force 'skip confirmation prompts'"))
.subcommand(SubCommand::with_name("build") .subcommand(SubCommand::with_name("build")
.about("Build the book from the markdown files") .about("Build the book from the markdown files")
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")) .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
.arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'"))
.subcommand(SubCommand::with_name("watch") .subcommand(SubCommand::with_name("watch")
.about("Watch the files for changes") .about("Watch the files for changes")
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")) .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
.arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'"))
.subcommand(SubCommand::with_name("serve") .subcommand(SubCommand::with_name("serve")
.about("Serve the book at http://localhost:3000. Rebuild and reload on change.") .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'") .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'")
.arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
.arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'") .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
.arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'") .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'")
.arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'") .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'")
.arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface addres)'")) .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface addres)'")
.arg_from_usage("-o, --open 'Open the compiled book in a web browser'"))
.subcommand(SubCommand::with_name("test") .subcommand(SubCommand::with_name("test")
.about("Test that code samples compile")) .about("Test that code samples compile"))
.get_matches(); .get_matches();
@ -106,10 +117,36 @@ fn confirm() -> bool {
} }
} }
// Init command implementation /// Init command implementation
///
/// It creates some boilerplate files and directories to get you started with your book.
///
/// ```text
/// thebook/
/// ├── book.toml
/// └── src
/// ├── SUMMARY.md
/// ├── first-chapter.md
/// ├── glossary.md
/// └── introduction.md
/// ```
///
/// It copies the embedded starter book as stored in data/book-init.
fn init(args: &ArgMatches) -> Result<(), Box<Error>> { fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
debug!("[fn]: init");
let book_dir = get_book_dir(args); let book_dir = get_book_dir(args);
if !book_dir.exists() {
fs::create_dir_all(&book_dir).unwrap();
info!("{:?} created", &book_dir);
}
try!(utils::fs::copy_data("data/book-init/*",
"data/book-init/",
vec![],
&book_dir));
let mut book_project = MDBook::new(&book_dir); let mut book_project = MDBook::new(&book_dir);
book_project.read_config(); book_project.read_config();
@ -134,8 +171,8 @@ fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
} }
// Copy the assets // Copy the assets
try!(utils::fs::copy_data("data/**/*", try!(utils::fs::copy_data("data/assets/**/*",
"data/", "data/assets/",
vec![], vec![],
&book_project.get_project_root().join("assets"))); &book_project.get_project_root().join("assets")));
@ -154,6 +191,7 @@ fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
println!("\nAll done, no errors..."); println!("\nAll done, no errors...");
debug!("[*]: init done");
Ok(()) Ok(())
} }
@ -161,9 +199,18 @@ fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
fn build(args: &ArgMatches) -> Result<(), Box<Error>> { fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
let book_dir = get_book_dir(args); let book_dir = get_book_dir(args);
let mut dest_base: Option<PathBuf> = None;
if let Some(p) = args.value_of("dest-dir") {
dest_base = Some(PathBuf::from(p));
}
// TODO select render format intent when we acutally have different renderers // TODO select render format intent when we acutally have different renderers
let renderer = HtmlHandlebars::new(); let renderer = HtmlHandlebars::new();
try!(renderer.build(&book_dir)); let book_project: MDBook = try!(renderer.build(&book_dir, &dest_base));
if args.is_present("open") {
open(book_project.get_dest_base().join("index.html"));
}
Ok(()) Ok(())
} }
@ -172,22 +219,28 @@ fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
#[cfg(feature = "watch")] #[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> { fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
let book_dir = get_book_dir(args); let book_dir = get_book_dir(args);
let mut book = MDBook::new(&book_dir);
book.read_config();
// |event, book| let mut dest_base: Option<PathBuf> = None;
trigger_on_change(&mut book, |event, _| { if let Some(p) = args.value_of("dest-dir") {
if let Some(path) = event.path { dest_base = Some(PathBuf::from(p));
}
let renderer = HtmlHandlebars::new();
let mut book_project: MDBook = try!(renderer.build(&book_dir, &dest_base));
if args.is_present("open") {
open(book_project.get_dest_base().join("index.html"));
}
trigger_on_change(&mut book_project, |path, _| {
println!("File changed: {:?}\nBuilding book...\n", path); println!("File changed: {:?}\nBuilding book...\n", path);
// TODO select render format intent when we acutally have different renderers // TODO select render format intent when we acutally have different renderers
let renderer = HtmlHandlebars::new(); let renderer = HtmlHandlebars::new();
match renderer.build(&book_dir) { match renderer.build(&book_dir, &dest_base) {
Err(e) => println!("Error while building: {:?}", e), Err(e) => println!("Error while building: {:?}", e),
_ => {}, _ => {},
} }
println!(""); println!("");
}
}); });
println!("watch"); println!("watch");
@ -200,8 +253,20 @@ fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
const RELOAD_COMMAND: &'static str = "reload"; const RELOAD_COMMAND: &'static str = "reload";
let book_dir = get_book_dir(args); let book_dir = get_book_dir(args);
let mut dest_base: Option<PathBuf> = None;
if let Some(p) = args.value_of("dest-dir") {
dest_base = Some(PathBuf::from(p));
}
let mut book = MDBook::new(&book_dir); let mut book = MDBook::new(&book_dir);
book.read_config(); book.read_config();
if let Some(p) = dest_base {
book.set_dest_base(&p);
}
book.parse_books(); book.parse_books();
book.link_translations(); book.link_translations();
@ -209,6 +274,7 @@ fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
let ws_port = args.value_of("ws-port").unwrap_or("3001"); let ws_port = args.value_of("ws-port").unwrap_or("3001");
let interface = args.value_of("interface").unwrap_or("localhost"); let interface = args.value_of("interface").unwrap_or("localhost");
let public_address = args.value_of("address").unwrap_or(interface); let public_address = args.value_of("address").unwrap_or(interface);
let open_browser = args.is_present("open");
let address = format!("{}:{}", interface, port); let address = format!("{}:{}", interface, port);
let ws_address = format!("{}:{}", interface, ws_port); let ws_address = format!("{}:{}", interface, ws_port);
@ -250,8 +316,11 @@ fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
println!("\nServing on {}", address); println!("\nServing on {}", address);
trigger_on_change(&mut book, move |event, book| { if open_browser {
if let Some(path) = event.path { open(format!("http://{}", address));
}
trigger_on_change(&mut book, move |path, book| {
println!("File changed: {:?}\nBuilding book...\n", path); println!("File changed: {:?}\nBuilding book...\n", path);
let renderer = HtmlHandlebars::new(); let renderer = HtmlHandlebars::new();
match renderer.render(&book) { match renderer.render(&book) {
@ -259,7 +328,6 @@ fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
_ => broadcaster.send(RELOAD_COMMAND).unwrap(), _ => broadcaster.send(RELOAD_COMMAND).unwrap(),
} }
println!(""); println!("");
}
}); });
Ok(()) Ok(())
@ -319,61 +387,64 @@ fn get_book_dir(args: &ArgMatches) -> PathBuf {
} }
} }
fn open<P: AsRef<OsStr>>(path: P) {
if let Err(e) = open::that(path) {
println!("Error opening web browser: {}", e);
}
}
// Calls the closure when a book source file is changed. This is blocking! // Calls the closure when a book source file is changed. This is blocking!
#[cfg(feature = "watch")] #[cfg(feature = "watch")]
fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> () fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
where F: Fn(notify::Event, &mut MDBook) -> () where F: Fn(&Path, &mut MDBook) -> ()
{ {
use notify::RecursiveMode::*;
use notify::DebouncedEvent::*;
// Create a channel to receive the events. // Create a channel to receive the events.
let (tx, rx) = channel(); let (tx, rx) = channel();
let w: Result<notify::RecommendedWatcher, notify::Error> = notify::Watcher::new(tx); let mut watcher = match notify::watcher(tx, Duration::from_secs(1)) {
Ok(w) => w,
match w { Err(e) => {
Ok(mut watcher) => { println!("Error while trying to watch the files:\n\n\t{:?}", e);
// Add the source directory to the watcher ::std::process::exit(2);
if let Err(e) = watcher.watch(book.get_src_base()) { }
println!("Error while watching {:?}:\n {:?}", book.get_src_base(), e);
::std::process::exit(0);
}; };
// Add the book.toml or book.json file to the watcher if it exists, // Add the source directory to the watcher
// because it's not located in the source directory if let Err(e) = watcher.watch(book.get_src_base(), Recursive) {
println!("Error while watching {:?}:\n {:?}", book.get_src_base(), e);
::std::process::exit(2);
};
if let Err(_) = watcher.watch(book.get_project_root().join("book.toml")) { // Add the book.{json,toml} file to the watcher if it exists, because it's not
// do nothing if book.toml is not found // located in the source directory
} if let Err(_) = watcher.watch(book.get_project_root().join("book.json"), NonRecursive) {
if let Err(_) = watcher.watch(book.get_project_root().join("book.json")) {
// do nothing if book.json is not found // do nothing if book.json is not found
} }
if let Err(_) = watcher.watch(book.get_project_root().join("book.toml"), NonRecursive) {
let mut previous_time = time::get_time(); // do nothing if book.toml is not found
}
println!("\nListening for changes...\n"); println!("\nListening for changes...\n");
loop { loop {
match rx.recv() { match rx.recv() {
Ok(event) => { Ok(event) => match event {
// Skip the event if an event has already been issued in the last second NoticeWrite(path) |
let time = time::get_time(); NoticeRemove(path) |
if time - previous_time < time::Duration::seconds(1) { Create(path) |
continue; Write(path) |
} else { Remove(path) |
previous_time = time; Rename(_, path) => {
closure(&path, book);
} }
_ => {}
closure(event, book);
}, },
Err(e) => { Err(e) => {
println!("An error occured: {:?}", e); println!("An error occured: {:?}", e);
}, },
} }
} }
},
Err(e) => {
println!("Error while trying to watch the files:\n\n\t{:?}", e);
::std::process::exit(0);
},
}
} }

View File

@ -1,6 +1,4 @@
use std::fs::File; use std::path::PathBuf;
use std::path::{Path, PathBuf};
use book::bookconfig::BookConfig; use book::bookconfig::BookConfig;
use book::toc::{TocItem, TocContent}; use book::toc::{TocItem, TocContent};

View File

@ -1,13 +1,8 @@
extern crate toml; extern crate toml;
use std::process::exit;
use std::fs::File;
use std::io::Read;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::str::FromStr;
use serde_json;
use utils; use utils;

View File

@ -4,10 +4,9 @@ extern crate toml;
use regex::Regex; use regex::Regex;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use std::fs::File; use std::fs::File;
use std::error::Error; use std::io::Read;
use std::io::{self, Read};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use utils; use utils;
@ -130,7 +129,7 @@ impl Chapter {
debug!("[*] Creating: {:?}", src_path); debug!("[*] Creating: {:?}", src_path);
match create_with_str(src_path, &format!("# {}", self.title)) { match create_with_str(src_path, &format!("# {}", self.title)) {
Ok(_) => { return Ok(self); }, Ok(_) => { return Ok(self); },
Err(e) => { Err(_) => {
return Err(format!("Could not create: {:?}", src_path)); return Err(format!("Could not create: {:?}", src_path));
}, },
} }
@ -140,8 +139,12 @@ impl Chapter {
match File::open(src_path) { match File::open(src_path) {
Err(e) => { return Err(format!("Read error: {:?}", e)); }, Err(e) => { return Err(format!("Read error: {:?}", e)); },
Ok(mut f) => { Ok(mut f) => {
// TODO try! here and return error match f.read_to_string(&mut text) {
f.read_to_string(&mut text); Ok(_) => {},
Err(e) => {
return Err(format!("Error: {:#?}", e));
},
}
self.content = Some(utils::strip_toml_header(&text)); self.content = Some(utils::strip_toml_header(&text));
} }
} }

View File

@ -9,8 +9,6 @@ pub mod toc;
pub mod chapter; pub mod chapter;
pub use self::book::Book; pub use self::book::Book;
use renderer::{Renderer, HtmlHandlebars};
use self::chapter::TranslationLink; use self::chapter::TranslationLink;
use self::toc::{TocItem, TocContent}; use self::toc::{TocItem, TocContent};
use utils; use utils;
@ -19,9 +17,6 @@ use std::env;
use std::process::exit; use std::process::exit;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::Read;
use std::error::Error;
use std::collections::{HashMap, BTreeMap}; use std::collections::{HashMap, BTreeMap};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -142,34 +137,6 @@ impl MDBook {
MDBook::default().set_project_root(project_root).clone() MDBook::default().set_project_root(project_root).clone()
} }
/// `init()` creates some boilerplate files and directories to get you started with your book.
///
/// ```text
/// book-example/
/// ├── book
/// └── src
/// ├── chapter_1.md
/// └── SUMMARY.md
/// ```
///
/// It uses the paths given as source and output directories and adds a `SUMMARY.md` and a
/// `chapter_1.md` to the source directory.
pub fn init(&mut self) -> Result<(), Box<Error>> {
debug!("[fn]: init");
if !self.project_root.exists() {
fs::create_dir_all(&self.project_root).unwrap();
info!("{:?} created", &self.project_root);
}
// Read book.toml if exists and populate .translations
self.read_config();
debug!("[*]: init done");
Ok(())
}
/// Parses the `book.toml` file (if it exists) to extract the configuration parameters. /// Parses the `book.toml` file (if it exists) to extract the configuration parameters.
/// The `book.toml` file should be in the root directory of the book project. /// The `book.toml` file should be in the root directory of the book project.
/// The project root directory is the one specified when creating a new `MDBook` /// The project root directory is the one specified when creating a new `MDBook`
@ -186,7 +153,6 @@ impl MDBook {
/// In this example, `project_root_dir` will be the root directory of our book and is specified in function /// In this example, `project_root_dir` will be the root directory of our book and is specified in function
/// of the current working directory by using a relative path instead of an absolute path. /// of the current working directory by using a relative path instead of an absolute path.
pub fn read_config(&mut self) -> &mut Self { pub fn read_config(&mut self) -> &mut Self {
debug!("[fn]: read_config"); debug!("[fn]: read_config");
// exit(2) is a clear indication for the user that something is wrong // exit(2) is a clear indication for the user that something is wrong
@ -194,7 +160,7 @@ impl MDBook {
// Read book.toml or book.json if exists to a BTreeMap // Read book.toml or book.json if exists to a BTreeMap
if Path::new(self.project_root.join("book.toml").as_os_str()).exists() { if self.project_root.join("book.toml").exists() {
debug!("[*]: Reading config"); debug!("[*]: Reading config");
let text = match utils::fs::file_to_string(&self.project_root.join("book.toml")) { let text = match utils::fs::file_to_string(&self.project_root.join("book.toml")) {
@ -213,7 +179,7 @@ impl MDBook {
} }
} }
} else if Path::new(self.project_root.join("book.json").as_os_str()).exists() { } else if self.project_root.join("book.json").exists() {
debug!("[*]: Reading config"); debug!("[*]: Reading config");
let text = match utils::fs::file_to_string(&self.project_root.join("book.json")) { let text = match utils::fs::file_to_string(&self.project_root.join("book.json")) {
@ -444,6 +410,8 @@ impl MDBook {
/// prepare a Vec of default links to point to the index.html of each translation /// prepare a Vec of default links to point to the index.html of each translation
pub fn translation_index_links(&self) -> Option<Vec<TranslationLink>> { pub fn translation_index_links(&self) -> Option<Vec<TranslationLink>> {
debug!("[fn] translation_index_links()");
let mut default_links: Vec<TranslationLink> = vec![]; let mut default_links: Vec<TranslationLink> = vec![];
let mut keys = self.translations.keys() let mut keys = self.translations.keys()
@ -578,6 +546,22 @@ impl MDBook {
} else { } else {
self.src_base = path.to_owned(); self.src_base = path.to_owned();
} }
let a = self.translations.clone();
let keys = a.keys();
let is_multilang: bool = keys.clone().count() > 1;
for key in keys {
if let Some(mut book) = self.translations.get_mut(key) {
if is_multilang {
book.config.src = self.src_base.join(key);
book.config.is_multilang = is_multilang;
} else {
book.config.src = self.src_base.to_owned();
}
}
}
self self
} }
@ -591,6 +575,22 @@ impl MDBook {
} else { } else {
self.dest_base = path.to_owned(); self.dest_base = path.to_owned();
} }
let a = self.translations.clone();
let keys = a.keys();
let is_multilang: bool = keys.clone().count() > 1;
for key in keys {
if let Some(mut book) = self.translations.get_mut(key) {
if is_multilang {
book.config.dest = self.dest_base.join(key);
book.config.is_multilang = is_multilang;
} else {
book.config.dest = self.dest_base.to_owned();
}
}
}
self self
} }

View File

@ -29,7 +29,7 @@
//! fn main() { //! fn main() {
//! let path = PathBuf::from("my-book"); // Path to the book project's root //! let path = PathBuf::from("my-book"); // Path to the book project's root
//! let renderer = HtmlHandlebars::new(); //! let renderer = HtmlHandlebars::new();
//! try!(renderer.build(&path)); // Build the book //! try!(renderer.build(&path, &None)); // Build the book
//! } //! }
//! ``` //! ```
//! //!

View File

@ -4,15 +4,12 @@ use book::{MDBook, Book};
use book::chapter::{Chapter, TranslationLink}; use book::chapter::{Chapter, TranslationLink};
use book::toc::{TocItem, TocContent}; use book::toc::{TocItem, TocContent};
use utils; use utils;
use FILES;
use std::process::exit; use std::process::exit;
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use std::ffi::OsStr; use std::fs;
use std::fs::{self, File};
use std::error::Error; use std::error::Error;
use std::io::{self, Read, Write}; use std::io::{self, Write};
use std::collections::BTreeMap;
use handlebars::Handlebars; use handlebars::Handlebars;
@ -30,13 +27,17 @@ impl HtmlHandlebars {
impl Renderer for HtmlHandlebars { impl Renderer for HtmlHandlebars {
/// Prepares the project and calls `render()`. /// Prepares the project and calls `render()`.
fn build(&self, project_root: &PathBuf) -> Result<(), Box<Error>> { fn build(&self, project_root: &PathBuf, dest_base: &Option<PathBuf>) -> Result<MDBook, Box<Error>> {
debug!("[fn]: build"); debug!("[fn]: build");
let mut book_project = MDBook::new(&project_root); let mut book_project = MDBook::new(&project_root);
book_project.read_config(); book_project.read_config();
if let Some(p) = dest_base.clone() {
book_project.set_dest_base(&p);
}
if !book_project.get_src_base().exists() { if !book_project.get_src_base().exists() {
println!("Source folder doesn't exist: {:?}", book_project.get_src_base()); println!("Source folder doesn't exist: {:?}", book_project.get_src_base());
exit(2); exit(2);
@ -55,11 +56,12 @@ impl Renderer for HtmlHandlebars {
} }
} }
Ok(()) Ok(book_project)
} }
/// Renders the chapters and copies static assets. /// Renders the chapters and copies static assets.
fn render(&self, book_project: &MDBook) -> Result<(), Box<Error>> { fn render(&self, book_project: &MDBook) -> Result<(), Box<Error>> {
debug!("[fn]: render");
debug!("[*]: Check if book's base output folder exists"); debug!("[*]: Check if book's base output folder exists");
if let Err(_) = fs::create_dir_all(&book_project.get_dest_base()) { if let Err(_) = fs::create_dir_all(&book_project.get_dest_base()) {
@ -82,11 +84,15 @@ impl Renderer for HtmlHandlebars {
let c = a.join("_*"); let c = a.join("_*");
let exclude_glob = c.to_str().unwrap(); let exclude_glob = c.to_str().unwrap();
// anyone wants to catch errors? // Ignoring all errors. Should try to see which types are worth returning.
utils::fs::copy_files(include_glob,
match utils::fs::copy_files(include_glob,
base, base,
vec![exclude_glob], vec![exclude_glob],
&book_project.get_dest_base()); &book_project.get_dest_base()) {
Ok(_) => {},
Err(_) => {},
}
} }
// Copy template's static assets // Copy template's static assets
@ -118,20 +124,23 @@ impl Renderer for HtmlHandlebars {
// ) // )
// } // }
// anyone wants to catch errors? // Ignoring all errors. Should try to see which types are worth returning.
utils::fs::copy_files(include_glob,
match utils::fs::copy_files(include_glob,
base, base,
vec![exclude_glob], vec![exclude_glob],
&book_project.get_dest_base()); &book_project.get_dest_base()) {
Ok(_) => {},
Err(_) => {},
}
} else { } else {
try!(utils::fs::copy_data("data/_html-template/**/*", try!(utils::fs::copy_data("data/assets/_html-template/**/*",
"data/_html-template/", "data/assets/_html-template/",
vec!["data/_html-template/_*"], vec!["data/assets/_html-template/_*"],
&book_project.get_dest_base())); &book_project.get_dest_base()));
} }
debug!("[fn]: render"); debug!("[*]: start rendering");
let mut handlebars = Handlebars::new(); let mut handlebars = Handlebars::new();
let translation_indexes = book_project.translation_index_links(); let translation_indexes = book_project.translation_index_links();
@ -159,7 +168,7 @@ impl Renderer for HtmlHandlebars {
let s = if let Some(p) = first_path_that_exists(&search_paths) { let s = if let Some(p) = first_path_that_exists(&search_paths) {
try!(utils::fs::file_to_string(&p)) try!(utils::fs::file_to_string(&p))
} else { } else {
try!(utils::fs::get_data_file("data/_html-template/_layouts/page.hbs")) try!(utils::fs::get_data_file("data/assets/_html-template/_layouts/page.hbs"))
}; };
// Register template // Register template
@ -194,7 +203,7 @@ impl Renderer for HtmlHandlebars {
} }
// Render the chapters of each book // Render the chapters of each book
for (key, book) in &book_project.translations { for (_, book) in &book_project.translations {
// Check if book's dest directory exists // Check if book's dest directory exists

View File

@ -1,5 +1,4 @@
use std::path::Path; use std::collections::VecDeque;
use std::collections::{VecDeque, BTreeMap};
use serde_json; use serde_json;
use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context}; use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context};

View File

@ -1,4 +1,3 @@
use std::path::Path;
use std::collections::{VecDeque, BTreeMap}; use std::collections::{VecDeque, BTreeMap};
use serde_json; use serde_json;

View File

@ -6,20 +6,27 @@ use book::MDBook;
use std::error::Error; use std::error::Error;
use std::path::PathBuf; use std::path::PathBuf;
// TODO refactor dest_base out of the .build() call. It's only here b/c to
// influence the build output with the --dest-dir CLI arg. It is a good
// thing though that .build() encapsulates the steps to prepare the MDBook
// struct for .render(). Maybe give it the CLI args and process them within
// .build().
pub trait Renderer { pub trait Renderer {
/// When the output format is determined (by a CLI argument for example), /// When the output format is determined (by a CLI argument for example),
/// call `.build()` of the selected Renderer implementation. /// call `.build()` of the selected Renderer implementation.
/// ///
/// Constructs an `MDBook` struct given the path of the book project, /// Constructs an `MDBook` struct given the path of the book project,
/// preparing the project and calling `render()`, doing what is necessary /// optionally using a custom output folder (such as when given with
/// for the particular output format. /// `--dest-dir` CLI argument). It prepares the project and calls
/// `render()`, doing what is necessary for the particular output format.
/// ///
/// This involves parsing config options from `book.toml` and parsing the /// This involves parsing config options from `book.toml` and parsing the
/// `SUMMARY.md` of each translation to a nested `Vec<TocItem>`. /// `SUMMARY.md` of each translation to a nested `Vec<TocItem>`.
/// ///
/// Finally it calls `render()` to process the chapters and static assets. /// Finally it calls `render()` to process the chapters and static assets.
fn build(&self, project_root: &PathBuf) -> Result<(), Box<Error>>; fn build(&self, project_root: &PathBuf, dest_base: &Option<PathBuf>) -> Result<MDBook, Box<Error>>;
/// Responsible for rendering the chapters and copying static assets. /// Responsible for rendering the chapters and copying static assets.
fn render(&self, book_project: &MDBook) -> Result<(), Box<Error>>; fn render(&self, book_project: &MDBook) -> Result<(), Box<Error>>;

View File

@ -1,7 +1,6 @@
#[cfg(test)] #![cfg(test)]
use std::path::PathBuf; use std::path::PathBuf;
use book::bookconfig::BookConfig; use book::bookconfig::BookConfig;
#[test] #[test]

View File

@ -1,7 +1,6 @@
#[cfg(test)] #![cfg(test)]
use std::path::PathBuf; use std::path::PathBuf;
use book::bookconfig::Author; use book::bookconfig::Author;
use book::chapter::Chapter; use book::chapter::Chapter;
@ -11,7 +10,12 @@ fn it_parses_when_exists() {
let path = PathBuf::from("at-the-mountains-of-madness.md"); let path = PathBuf::from("at-the-mountains-of-madness.md");
let mut result = Chapter::new("Mountains".to_string(), path.clone()); let mut result = Chapter::new("Mountains".to_string(), path.clone());
result.parse_or_create_using(&src_path); match result.parse_or_create_using(&src_path) {
Ok(_) => {},
Err(e) => {
println!("Error: {:#?}", e);
}
}
let mut expected = Chapter::new("Mountains".to_string(), path.clone()); let mut expected = Chapter::new("Mountains".to_string(), path.clone());

View File

@ -1,11 +1,10 @@
#[cfg(test)] #![cfg(test)]
extern crate tempdir; extern crate tempdir;
use std; use std;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::Read; use std::io::Read;
use std::path::Path;
use utils; use utils;
use utils::fs::copy_files_except_ext; use utils::fs::copy_files_except_ext;
@ -15,18 +14,21 @@ fn it_copies_data_file() {
let dest_base = std::env::temp_dir().join("in tangles of old alleys"); let dest_base = std::env::temp_dir().join("in tangles of old alleys");
let dest_path = dest_base.join("book.css"); let dest_path = dest_base.join("book.css");
utils::fs::copy_data_file("data/_html-template/css/books.css", &dest_path); match utils::fs::copy_data_file("data/assets/_html-template/css/books.css", &dest_path) {
Ok(_) => {},
Err(e) => { println!("{:#?}", e); }
}
let mut file = match File::open(&dest_path) { let mut file = match File::open(&dest_path) {
Ok(f) => f, Ok(f) => f,
Err(e) => { Err(_) => {
println!("Failed to open {:?}", dest_path); println!("Failed to open {:?}", dest_path);
return; return;
}, },
}; };
let mut content = String::new(); let mut content = String::new();
if let Err(e) = file.read_to_string(&mut content) { if let Err(_) = file.read_to_string(&mut content) {
println!("Failed to read {:?}", dest_path); println!("Failed to read {:?}", dest_path);
return; return;
} }
@ -34,7 +36,10 @@ fn it_copies_data_file() {
assert!(content.as_str().contains("Open Sans")); assert!(content.as_str().contains("Open Sans"));
if dest_base.exists() { if dest_base.exists() {
fs::remove_dir_all(dest_base); match fs::remove_dir_all(dest_base) {
Ok(_) => {},
Err(e) => { println!("{:#?}", e); },
}
} }
} }
@ -42,9 +47,9 @@ fn it_copies_data_file() {
fn it_copies_data_by_pattern() { fn it_copies_data_by_pattern() {
let dest_base = std::env::temp_dir().join("near the quays"); let dest_base = std::env::temp_dir().join("near the quays");
if let Err(e) = utils::fs::copy_data("data/_html-template/**/*", if let Err(e) = utils::fs::copy_data("data/assets/_html-template/**/*",
"data/_html-template/", "data/assets/_html-template/",
vec!["data/_html-template/_*"], vec!["data/assets/_html-template/_*"],
&dest_base) { &dest_base) {
println!("Error: {:#?}", e); println!("Error: {:#?}", e);
return; return;
@ -54,7 +59,10 @@ fn it_copies_data_by_pattern() {
assert!(!dest_base.join("_layouts").exists()); assert!(!dest_base.join("_layouts").exists());
if dest_base.exists() { if dest_base.exists() {
fs::remove_dir_all(dest_base); match fs::remove_dir_all(dest_base) {
Ok(_) => {},
Err(e) => { println!("{:#?}", e); },
}
} }
} }
@ -72,14 +80,20 @@ fn it_doesnt_delete_toplevel_dotfiles() {
Ok(_) => {}, Ok(_) => {},
} }
utils::fs::clean_output_dir(&dest_base); match utils::fs::clean_output_dir(&dest_base) {
Ok(_) => {},
Err(e) => { println!("{:#?}", e); }
}
assert!(dest_base.exists()); assert!(dest_base.exists());
assert!(dest_base.join(".dotfile").exists()); assert!(dest_base.join(".dotfile").exists());
assert!(!dest_base.join("door.html").exists()); assert!(!dest_base.join("door.html").exists());
if dest_base.exists() { if dest_base.exists() {
fs::remove_dir_all(dest_base); match fs::remove_dir_all(dest_base) {
Ok(_) => {},
Err(e) => { println!("{:#?}", e); },
}
} }
} }

View File

@ -1,4 +1,4 @@
#[cfg(test)] #![cfg(test)]
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -11,7 +11,7 @@ fn it_renders_multilanguage_book() {
let path = PathBuf::from(".").join("src").join("tests").join("book-wonderland-multilang"); let path = PathBuf::from(".").join("src").join("tests").join("book-wonderland-multilang");
let renderer = HtmlHandlebars::new(); let renderer = HtmlHandlebars::new();
if let Err(e) = renderer.build(&path) { if let Err(e) = renderer.build(&path, &None) {
panic!("{:#?}", e); panic!("{:#?}", e);
} }
@ -20,8 +20,8 @@ fn it_renders_multilanguage_book() {
proj.parse_books(); proj.parse_books();
let mut book_path: &Path = proj.translations.get("en").unwrap().config.get_dest(); let mut book_path: &Path = proj.translations.get("en").unwrap().config.get_dest();
let mut chapter_path: PathBuf = PathBuf::from("".to_string()); let mut chapter_path: PathBuf;
let mut s: String = String::new(); let mut s: String;
// Test if index.html in the project dest folder is the main book's first chapter // Test if index.html in the project dest folder is the main book's first chapter

View File

@ -1,4 +1,4 @@
#[cfg(test)] #![cfg(test)]
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -11,7 +11,7 @@ fn it_renders_html_from_minimal_book() {
let path = PathBuf::from(".").join("src").join("tests").join("book-minimal"); let path = PathBuf::from(".").join("src").join("tests").join("book-minimal");
let renderer = HtmlHandlebars::new(); let renderer = HtmlHandlebars::new();
if let Err(e) = renderer.build(&path) { if let Err(e) = renderer.build(&path, &None) {
println!("{:#?}", e); println!("{:#?}", e);
} }
@ -20,8 +20,8 @@ fn it_renders_html_from_minimal_book() {
proj.parse_books(); proj.parse_books();
let book_path: &Path = proj.translations.get("en").unwrap().config.get_dest(); let book_path: &Path = proj.translations.get("en").unwrap().config.get_dest();
let mut chapter_path: PathBuf = PathBuf::from("".to_string()); let mut chapter_path: PathBuf;
let mut s: String = String::new(); let mut s: String;
// Test if "Library of Babel" was rendered // Test if "Library of Babel" was rendered
@ -54,7 +54,7 @@ fn it_copies_local_assets_when_found() {
let path = PathBuf::from(".").join("src").join("tests").join("book-minimal-with-assets"); let path = PathBuf::from(".").join("src").join("tests").join("book-minimal-with-assets");
let renderer = HtmlHandlebars::new(); let renderer = HtmlHandlebars::new();
if let Err(e) = renderer.build(&path) { if let Err(e) = renderer.build(&path, &None) {
println!("{:#?}", e); println!("{:#?}", e);
} }
@ -64,13 +64,11 @@ fn it_copies_local_assets_when_found() {
let book_path: &Path = proj.translations.get("en").unwrap().config.get_dest(); let book_path: &Path = proj.translations.get("en").unwrap().config.get_dest();
let mut chapter_path: PathBuf = PathBuf::from("".to_string());
let mut s: String = String::new();
// Test if "Library of Babel" was rendered // Test if "Library of Babel" was rendered
chapter_path = book_path.join("fictions").join("babel").with_extension("html"); let chapter_path = book_path.join("fictions").join("babel").with_extension("html");
s = utils::fs::file_to_string(&chapter_path).unwrap(); let s = utils::fs::file_to_string(&chapter_path).unwrap();
assert!(s.contains("The Library of Babel")); assert!(s.contains("The Library of Babel"));
assert_eq!(book_path.join("css").join("book.css").exists(), true); assert_eq!(book_path.join("css").join("book.css").exists(), true);

View File

@ -1,18 +1,16 @@
#[cfg(test)] #![cfg(test)]
extern crate toml; extern crate toml;
use std::process::exit; use std::process::exit;
use std::path::PathBuf; use std::path::PathBuf;
use serde_json;
use utils; use utils;
use book::MDBook; use book::MDBook;
use book::book::Book; use book::book::Book;
use book::bookconfig::{BookConfig, Author, Language}; use book::bookconfig::{BookConfig, Author, Language};
use book::chapter::Chapter; use book::chapter::Chapter;
use book::toc::{TocItem, TocContent}; use book::toc::TocItem;
#[test] #[test]
fn it_parses_simple_json_config() { fn it_parses_simple_json_config() {

View File

@ -1,6 +1,4 @@
#[cfg(test)] #![cfg(test)]
use std::path::PathBuf;
use parse::summary::parse_level; use parse::summary::parse_level;

View File

@ -1,6 +1,5 @@
#[cfg(test)] #![cfg(test)]
use book::chapter::Chapter;
use book::toc::{TocItem, TocContent, flat_toc, toc_node_count_id}; use book::toc::{TocItem, TocContent, flat_toc, toc_node_count_id};
use parse::summary::parse_level; use parse::summary::parse_level;

View File

@ -1,9 +1,6 @@
#[cfg(test)] #![cfg(test)]
use std::collections::BTreeMap;
use serde_json; use serde_json;
use utils::*; use utils::*;
#[test] #[test]

View File

@ -61,17 +61,17 @@ pub fn copy_data_file(src_path: &str, dest_path: &Path) -> Result<(), Box<Error>
/// `include_base` will be removed from the source path. This way the path /// `include_base` will be removed from the source path. This way the path
/// relative to the `dest_path` can be controlled. /// relative to the `dest_path` can be controlled.
/// ///
/// The following will copy all files under "data/_html-template/", excluding /// The following will copy all files under "data/assets/_html-template/", excluding
/// folders that start with "_", take the "data/_html-template/" part off the /// folders that start with "_", take the "data/assets/_html-template/" part off the
/// source path, and write the entries to "assets" folder. /// source path, and write the entries to "assets" folder.
/// ///
/// I.e. "data/_html-template/css/book.css" will be written to /// I.e. "data/assets/_html-template/css/book.css" will be written to
/// "assets/css/book.css". /// "assets/css/book.css".
/// ///
/// ```ignore /// ```ignore
/// utils::fs::copy_data("data/_html-template/**/*", /// utils::fs::copy_data("data/assets/_html-template/**/*",
/// "data/_html-template/", /// "data/assets/_html-template/",
/// vec!["data/_html-template/_*"], /// vec!["data/assets/_html-template/_*"],
/// &Path::new("assets")); /// &Path::new("assets"));
/// ``` /// ```
pub fn copy_data(include_glob: &str, pub fn copy_data(include_glob: &str,
@ -221,7 +221,7 @@ pub fn path_to_root(path: &Path) -> String {
/// This function creates a file and returns it. But before creating the file it checks every /// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created. /// directory in the path to see if it exists, and if it does not it will be created.
pub fn create_file(path: &Path) -> Result<File, Box<Error>> { pub fn create_file(path: &Path) -> io::Result<File> {
debug!("[fn]: create_file"); debug!("[fn]: create_file");
// Construct path // Construct path
@ -232,15 +232,7 @@ pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
} }
debug!("[*]: Create file: {:?}", path); debug!("[*]: Create file: {:?}", path);
let f = match File::create(path) { File::create(path)
Ok(f) => f,
Err(e) => {
debug!("File::create: {}", e);
return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e))));
},
};
Ok(f)
} }
/// A cleaning operation intended to be used on the output directory of a book /// A cleaning operation intended to be used on the output directory of a book

View File

@ -4,7 +4,6 @@ extern crate toml;
use regex::Regex; use regex::Regex;
use std::str::FromStr; use std::str::FromStr;
use std::error::Error;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use serde_json; use serde_json;