Merge pull request #288 from budziq/rustfmt_update

Made changes with rustfmt including `use_try_shorthand`
This commit is contained in:
Mathieu David 2017-05-19 13:43:49 +02:00 committed by GitHub
commit f038dcb404
14 changed files with 402 additions and 320 deletions

View File

@ -20,7 +20,8 @@ fn main() {
.arg(format!("{}", theme_dir.to_str().unwrap()))
.arg("--use")
.arg("nib")
.status().unwrap()
.status()
.unwrap()
.success() {
panic!("Stylus encoutered an error");
}

View File

@ -10,6 +10,7 @@ enum_trailing_comma = true
match_block_trailing_comma = true
struct_trailing_comma = "Always"
wrap_comments = true
use_try_shorthand = true
report_todo = "Always"
report_fixme = "Always"

View File

@ -121,7 +121,7 @@ fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
let mut book = MDBook::new(&book_dir);
// Call the function that does the initialization
try!(book.init());
book.init()?;
// If flag `--theme` is present, copy theme to src
if args.is_present("theme") {
@ -142,7 +142,7 @@ fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
}
// Call the function that copies the theme
try!(book.copy_theme());
book.copy_theme()?;
println!("\nTheme copied.");
}
@ -172,14 +172,14 @@ fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
let mut book = match args.value_of("dest-dir") {
Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
None => book
None => book,
};
if args.is_present("no-create") {
book.create_missing = false;
}
try!(book.build());
book.build()?;
if args.is_present("open") {
open(book.get_dest().join("index.html"));
@ -197,11 +197,11 @@ fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
let mut book = match args.value_of("dest-dir") {
Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
None => book
None => book,
};
if args.is_present("open") {
try!(book.build());
book.build()?;
open(book.get_dest().join("index.html"));
}
@ -227,7 +227,7 @@ fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
let mut book = match args.value_of("dest-dir") {
Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
None => book
None => book,
};
let port = args.value_of("port").unwrap_or("3000");
@ -253,25 +253,22 @@ fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
socket.close();
}}
</script>
"#, public_address, ws_port, RELOAD_COMMAND).to_owned());
"#,
public_address,
ws_port,
RELOAD_COMMAND));
try!(book.build());
book.build()?;
let staticfile = staticfile::Static::new(book.get_dest());
let iron = iron::Iron::new(staticfile);
let _iron = iron.http(&*address).unwrap();
let ws_server = ws::WebSocket::new(|_| {
|_| {
Ok(())
}
}).unwrap();
let ws_server = ws::WebSocket::new(|_| |_| Ok(())).unwrap();
let broadcaster = ws_server.broadcaster();
std::thread::spawn(move || {
ws_server.listen(&*ws_address).unwrap();
});
std::thread::spawn(move || { ws_server.listen(&*ws_address).unwrap(); });
println!("\nServing on {}", address);
@ -296,7 +293,7 @@ fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
let book_dir = get_book_dir(args);
let mut book = MDBook::new(&book_dir).read_config();
try!(book.test());
book.test()?;
Ok(())
}
@ -339,7 +336,7 @@ fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
Err(e) => {
println!("Error while trying to watch the files:\n\n\t{:?}", e);
::std::process::exit(0);
}
},
};
// Add the source directory to the watcher
@ -350,10 +347,14 @@ fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
// Add the book.{json,toml} file to the watcher if it exists, because it's not
// located in the source directory
if watcher.watch(book.get_root().join("book.json"), NonRecursive).is_err() {
if watcher
.watch(book.get_root().join("book.json"), NonRecursive)
.is_err() {
// do nothing if book.json is not found
}
if watcher.watch(book.get_root().join("book.toml"), NonRecursive).is_err() {
if watcher
.watch(book.get_root().join("book.toml"), NonRecursive)
.is_err() {
// do nothing if book.toml is not found
}
@ -361,7 +362,8 @@ fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
loop {
match rx.recv() {
Ok(event) => match event {
Ok(event) => {
match event {
NoticeWrite(path) |
NoticeRemove(path) |
Create(path) |
@ -369,8 +371,9 @@ fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
Remove(path) |
Rename(_, path) => {
closure(&path, book);
},
_ => {},
}
_ => {}
},
Err(e) => {
println!("An error occured: {:?}", e);

View File

@ -53,7 +53,7 @@ impl BookConfig {
Err(_) => {
error!("[*]: Failed to open {:?}", &path);
exit(2);
}
},
};
if f.read_to_string(&mut data).is_err() {
error!("[*]: Failed to read {:?}", &path);
@ -85,11 +85,11 @@ impl BookConfig {
pub fn parse_from_toml_string(&mut self, data: &str) -> &mut Self {
let config = match toml::from_str(data) {
Ok(x) => {x},
Ok(x) => x,
Err(e) => {
error!("[*]: Toml parse errors in book.toml: {:?}", e);
exit(2);
}
},
};
self.parse_from_btreemap(&config);
@ -97,7 +97,8 @@ impl BookConfig {
self
}
/// Parses the string to JSON and converts it to BTreeMap<String, toml::Value>.
/// Parses the string to JSON and converts it
/// to BTreeMap<String, toml::Value>.
pub fn parse_from_json_string(&mut self, data: &str) -> &mut Self {
let c: serde_json::Value = match serde_json::from_str(data) {
@ -105,7 +106,7 @@ impl BookConfig {
Err(e) => {
error!("[*]: JSON parse errors in book.json: {:?}", e);
exit(2);
}
},
};
let config = json_object_to_btreemap(c.as_object().unwrap());
@ -205,10 +206,7 @@ pub fn json_object_to_btreemap(json: &serde_json::Map<String, serde_json::Value>
let mut config: BTreeMap<String, toml::Value> = BTreeMap::new();
for (key, value) in json.iter() {
config.insert(
String::from_str(key).unwrap(),
json_value_to_toml_value(value.to_owned())
);
config.insert(String::from_str(key).unwrap(), json_value_to_toml_value(value.to_owned()));
}
config
@ -223,10 +221,10 @@ pub fn json_value_to_toml_value(json: serde_json::Value) -> toml::Value {
serde_json::Value::Number(x) => toml::Value::Float(x.as_f64().unwrap()),
serde_json::Value::String(x) => toml::Value::String(x),
serde_json::Value::Array(x) => {
toml::Value::Array(x.iter().map(|v| json_value_to_toml_value(v.to_owned())).collect())
},
serde_json::Value::Object(x) => {
toml::Value::Table(json_object_to_btreemap(&x))
toml::Value::Array(x.iter()
.map(|v| json_value_to_toml_value(v.to_owned()))
.collect())
},
serde_json::Value::Object(x) => toml::Value::Table(json_object_to_btreemap(&x)),
}
}

View File

@ -37,10 +37,12 @@ impl Chapter {
impl Serialize for Chapter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
let mut struct_ = try!(serializer.serialize_struct("Chapter", 2));
try!(struct_.serialize_field("name", &self.name));
try!(struct_.serialize_field("path", &self.path));
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut struct_ = serializer.serialize_struct("Chapter", 2)?;
struct_.serialize_field("name", &self.name)?;
struct_.serialize_field("path", &self.path)?;
struct_.end()
}
}
@ -66,7 +68,8 @@ impl<'a> Iterator for BookItems<'a> {
let cur = &self.items[self.current_index];
match *cur {
BookItem::Chapter(_, ref ch) | BookItem::Affix(ref ch) => {
BookItem::Chapter(_, ref ch) |
BookItem::Affix(ref ch) => {
self.stack.push((self.items, self.current_index));
self.items = &ch.sub_items[..];
self.current_index = 0;

View File

@ -54,8 +54,10 @@ impl MDBook {
/// # }
/// ```
///
/// In this example, `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.
/// In this example, `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.
///
/// Default directory paths:
///
@ -63,7 +65,8 @@ impl MDBook {
/// - output: `root/book`
/// - theme: `root/theme`
///
/// They can both be changed by using [`set_src()`](#method.set_src) and [`set_dest()`](#method.set_dest)
/// They can both be changed by using [`set_src()`](#method.set_src) and
/// [`set_dest()`](#method.set_dest)
pub fn new(root: &Path) -> MDBook {
@ -90,7 +93,8 @@ impl MDBook {
}
}
/// Returns a flat depth-first iterator over the elements of the book, it returns an [BookItem enum](bookitem.html):
/// Returns a flat depth-first iterator over the elements of the book,
/// it returns an [BookItem enum](bookitem.html):
/// `(section: String, bookitem: &BookItem)`
///
/// ```no_run
@ -126,7 +130,8 @@ impl MDBook {
}
}
/// `init()` creates some boilerplate files and directories to get you started with your book.
/// `init()` creates some boilerplate files and directories
/// to get you started with your book.
///
/// ```text
/// book-test/
@ -136,7 +141,8 @@ impl MDBook {
/// └── SUMMARY.md
/// ```
///
/// It uses the paths given as source and output directories and adds a `SUMMARY.md` and a
/// 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>> {
@ -152,12 +158,12 @@ impl MDBook {
if !self.dest.exists() {
debug!("[*]: {:?} does not exist, trying to create directory", self.dest);
try!(fs::create_dir_all(&self.dest));
fs::create_dir_all(&self.dest)?;
}
if !self.src.exists() {
debug!("[*]: {:?} does not exist, trying to create directory", self.src);
try!(fs::create_dir_all(&self.src));
fs::create_dir_all(&self.src)?;
}
let summary = self.src.join("SUMMARY.md");
@ -167,18 +173,18 @@ impl MDBook {
// Summary does not exist, create it
debug!("[*]: {:?} does not exist, trying to create SUMMARY.md", self.src.join("SUMMARY.md"));
let mut f = try!(File::create(&self.src.join("SUMMARY.md")));
let mut f = File::create(&self.src.join("SUMMARY.md"))?;
debug!("[*]: Writing to SUMMARY.md");
try!(writeln!(f, "# Summary"));
try!(writeln!(f, ""));
try!(writeln!(f, "- [Chapter 1](./chapter_1.md)"));
writeln!(f, "# Summary")?;
writeln!(f, "")?;
writeln!(f, "- [Chapter 1](./chapter_1.md)")?;
}
}
// parse SUMMARY.md, and create the missing item related file
try!(self.parse_summary());
self.parse_summary()?;
debug!("[*]: constructing paths for missing files");
for item in self.iter() {
@ -193,16 +199,15 @@ impl MDBook {
if !path.exists() {
if !self.create_missing {
return Err(format!(
"'{}' referenced from SUMMARY.md does not exist.",
path.to_string_lossy()).into());
return Err(format!("'{}' referenced from SUMMARY.md does not exist.", path.to_string_lossy())
.into());
}
debug!("[*]: {:?} does not exist, trying to create file", path);
try!(::std::fs::create_dir_all(path.parent().unwrap()));
let mut f = try!(File::create(path));
::std::fs::create_dir_all(path.parent().unwrap())?;
let mut f = File::create(path)?;
// debug!("[*]: Writing to {:?}", path);
try!(writeln!(f, "# {}", ch.name));
writeln!(f, "# {}", ch.name)?;
}
}
}
@ -217,8 +222,9 @@ impl MDBook {
if !gitignore.exists() {
// Gitignore does not exist, create it
// Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root`. If it
// is not, `strip_prefix` will return an Error.
// Because of `src/book/mdbook.rs#L37-L39`,
// `dest` will always start with `root`.
// If it is not, `strip_prefix` will return an Error.
if !self.get_dest().starts_with(&self.root) {
return;
}
@ -226,7 +232,8 @@ impl MDBook {
let relative = self.get_dest()
.strip_prefix(&self.root)
.expect("Destination is not relative to root.");
let relative = relative.to_str()
let relative = relative
.to_str()
.expect("Path could not be yielded into a string slice.");
debug!("[*]: {:?} does not exist, trying to create .gitignore", gitignore);
@ -239,20 +246,21 @@ impl MDBook {
}
}
/// The `build()` method is the one where everything happens. First it parses `SUMMARY.md` to
/// construct the book's structure in the form of a `Vec<BookItem>` and then calls `render()`
/// The `build()` method is the one where everything happens.
/// First it parses `SUMMARY.md` to construct the book's structure
/// in the form of a `Vec<BookItem>` and then calls `render()`
/// method of the current renderer.
///
/// It is the renderer who generates all the output files.
pub fn build(&mut self) -> Result<(), Box<Error>> {
debug!("[fn]: build");
try!(self.init());
self.init()?;
// Clean output directory
try!(utils::fs::remove_dir_content(&self.dest));
utils::fs::remove_dir_content(&self.dest)?;
try!(self.renderer.render(&self));
self.renderer.render(&self)?;
Ok(())
}
@ -269,47 +277,46 @@ impl MDBook {
if !theme_dir.exists() {
debug!("[*]: {:?} does not exist, trying to create directory", theme_dir);
try!(fs::create_dir(&theme_dir));
fs::create_dir(&theme_dir)?;
}
// index.hbs
let mut index = try!(File::create(&theme_dir.join("index.hbs")));
try!(index.write_all(theme::INDEX));
let mut index = File::create(&theme_dir.join("index.hbs"))?;
index.write_all(theme::INDEX)?;
// book.css
let mut css = try!(File::create(&theme_dir.join("book.css")));
try!(css.write_all(theme::CSS));
let mut css = File::create(&theme_dir.join("book.css"))?;
css.write_all(theme::CSS)?;
// favicon.png
let mut favicon = try!(File::create(&theme_dir.join("favicon.png")));
try!(favicon.write_all(theme::FAVICON));
let mut favicon = File::create(&theme_dir.join("favicon.png"))?;
favicon.write_all(theme::FAVICON)?;
// book.js
let mut js = try!(File::create(&theme_dir.join("book.js")));
try!(js.write_all(theme::JS));
let mut js = File::create(&theme_dir.join("book.js"))?;
js.write_all(theme::JS)?;
// highlight.css
let mut highlight_css = try!(File::create(&theme_dir.join("highlight.css")));
try!(highlight_css.write_all(theme::HIGHLIGHT_CSS));
let mut highlight_css = File::create(&theme_dir.join("highlight.css"))?;
highlight_css.write_all(theme::HIGHLIGHT_CSS)?;
// highlight.js
let mut highlight_js = try!(File::create(&theme_dir.join("highlight.js")));
try!(highlight_js.write_all(theme::HIGHLIGHT_JS));
let mut highlight_js = File::create(&theme_dir.join("highlight.js"))?;
highlight_js.write_all(theme::HIGHLIGHT_JS)?;
Ok(())
}
pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<(), Box<Error>> {
let path = self.get_dest().join(filename);
try!(utils::fs::create_file(&path).and_then(|mut file| {
file.write_all(content)
}).map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("Could not create {}: {}", path.display(), e))
}));
utils::fs::create_file(&path)
.and_then(|mut file| file.write_all(content))
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Could not create {}: {}", path.display(), e)))?;
Ok(())
}
/// Parses the `book.json` file (if it exists) to extract the configuration parameters.
/// Parses the `book.json` file (if it exists) to extract
/// the configuration parameters.
/// The `book.json` file should be in the root directory of the book.
/// The root directory is the one specified when creating a new `MDBook`
@ -330,8 +337,10 @@ impl MDBook {
self
}
/// You can change the default renderer to another one by using this method. The only requirement
/// is for your renderer to implement the [Renderer trait](../../renderer/renderer/trait.Renderer.html)
/// You can change the default renderer to another one
/// by using this method. The only requirement
/// is for your renderer to implement the
/// [Renderer trait](../../renderer/renderer/trait.Renderer.html)
///
/// ```no_run
/// extern crate mdbook;
@ -343,12 +352,14 @@ impl MDBook {
/// let mut book = MDBook::new(Path::new("mybook"))
/// .set_renderer(Box::new(HtmlHandlebars::new()));
///
/// // In this example we replace the default renderer by the default renderer...
/// // In this example we replace the default renderer
/// // by the default renderer...
/// // Don't forget to put your renderer in a Box
/// }
/// ```
///
/// **note:** Don't forget to put your renderer in a `Box` before passing it to `set_renderer()`
/// **note:** Don't forget to put your renderer in a `Box`
/// before passing it to `set_renderer()`
pub fn set_renderer(mut self, renderer: Box<Renderer>) -> Self {
self.renderer = renderer;
@ -357,7 +368,7 @@ impl MDBook {
pub fn test(&mut self) -> Result<(), Box<Error>> {
// read in the chapters
try!(self.parse_summary());
self.parse_summary()?;
for item in self.iter() {
if let BookItem::Chapter(_, ref ch) = *item {
@ -367,17 +378,15 @@ impl MDBook {
println!("[*]: Testing file: {:?}", path);
let output_result = Command::new("rustdoc")
.arg(&path)
.arg("--test")
.output();
let output = try!(output_result);
let output_result = Command::new("rustdoc").arg(&path).arg("--test").output();
let output = output_result?;
if !output.status.success() {
return Err(Box::new(io::Error::new(ErrorKind::Other, format!(
"{}\n{}",
return Err(Box::new(io::Error::new(ErrorKind::Other,
format!("{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)))) as Box<Error>);
String::from_utf8_lossy(&output.stderr)))) as
Box<Error>);
}
}
}
@ -480,7 +489,7 @@ impl MDBook {
// Construct book
fn parse_summary(&mut self) -> Result<(), Box<Error>> {
// When append becomes stable, use self.content.append() ...
self.content = try!(parse::construct_bookitems(&self.src.join("SUMMARY.md")));
self.content = parse::construct_bookitems(&self.src.join("SUMMARY.md"))?;
Ok(())
}
}

View File

@ -76,7 +76,8 @@ extern crate handlebars;
extern crate pulldown_cmark;
extern crate regex;
#[macro_use] extern crate log;
#[macro_use]
extern crate log;
pub mod book;
mod parse;
pub mod renderer;

View File

@ -6,10 +6,10 @@ use book::bookitem::{BookItem, Chapter};
pub fn construct_bookitems(path: &PathBuf) -> Result<Vec<BookItem>> {
debug!("[fn]: construct_bookitems");
let mut summary = String::new();
try!(try!(File::open(path)).read_to_string(&mut summary));
File::open(path)?.read_to_string(&mut summary)?;
debug!("[*]: Parse SUMMARY.md");
let top_items = try!(parse_level(&mut summary.split('\n').collect(), 0, vec![0]));
let top_items = parse_level(&mut summary.split('\n').collect(), 0, vec![0])?;
debug!("[*]: Done parsing SUMMARY.md");
Ok(top_items)
}
@ -22,9 +22,10 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec<i32
while !summary.is_empty() {
let item: BookItem;
// Indentation level of the line to parse
let level = try!(level(summary[0], 4));
let level = level(summary[0], 4)?;
// if level < current_level we remove the last digit of section, exit the current function,
// if level < current_level we remove the last digit of section,
// exit the current function,
// and return the parsed level to the calling function.
if level < current_level {
break;
@ -35,11 +36,13 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec<i32
// Level can not be root level !!
// Add a sub-number to section
section.push(0);
let last = items.pop().expect("There should be at least one item since this can't be the root level");
let last = items
.pop()
.expect("There should be at least one item since this can't be the root level");
if let BookItem::Chapter(ref s, ref ch) = last {
let mut ch = ch.clone();
ch.sub_items = try!(parse_level(summary, level, section.clone()));
ch.sub_items = parse_level(summary, level, section.clone())?;
items.push(BookItem::Chapter(s.clone(), ch));
// Remove the last number from the section, because we got back to our level..
@ -62,7 +65,8 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec<i32
// Eliminate possible errors and set section to -1 after suffix
match parsed_item {
// error if level != 0 and BookItem is != Chapter
BookItem::Affix(_) | BookItem::Spacer if level > 0 => {
BookItem::Affix(_) |
BookItem::Spacer if level > 0 => {
return Err(Error::new(ErrorKind::Other,
"Your summary.md is messed up\n\n
\
@ -98,7 +102,9 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec<i32
// Increment section
let len = section.len() - 1;
section[len] += 1;
let s = section.iter().fold("".to_owned(), |s, i| s + &i.to_string() + ".");
let s = section
.iter()
.fold("".to_owned(), |s, i| s + &i.to_string() + ".");
BookItem::Chapter(s, ch)
},
_ => parsed_item,

View File

@ -37,7 +37,8 @@ impl Renderer for HtmlHandlebars {
// Register template
debug!("[*]: Register handlebars template");
try!(handlebars.register_template_string("index", try!(String::from_utf8(theme.index))));
handlebars
.register_template_string("index", String::from_utf8(theme.index)?)?;
// Register helpers
debug!("[*]: Register handlebars helpers");
@ -45,7 +46,7 @@ impl Renderer for HtmlHandlebars {
handlebars.register_helper("previous", Box::new(helpers::navigation::previous));
handlebars.register_helper("next", Box::new(helpers::navigation::next));
let mut data = try!(make_data(book));
let mut data = make_data(book)?;
// Print version
let mut print_content: String = String::new();
@ -69,11 +70,11 @@ impl Renderer for HtmlHandlebars {
let path = book.get_src().join(&ch.path);
debug!("[*]: Opening file: {:?}", path);
let mut f = try!(File::open(&path));
let mut f = File::open(&path)?;
let mut content: String = String::new();
debug!("[*]: Reading file");
try!(f.read_to_string(&mut content));
f.read_to_string(&mut content)?;
// Parse for playpen links
if let Some(p) = path.parent() {
@ -85,8 +86,10 @@ impl Renderer for HtmlHandlebars {
print_content.push_str(&content);
// Update the context with data for this file
let path = ch.path.to_str().ok_or_else(||
io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))?;
let path =
ch.path
.to_str()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))?;
data.insert("path".to_owned(), json!(path));
data.insert("content".to_owned(), json!(content));
data.insert("chapter_title".to_owned(), json!(ch.name));
@ -94,7 +97,7 @@ impl Renderer for HtmlHandlebars {
// Render the handlebars template with the data
debug!("[*]: Render template");
let rendered = try!(handlebars.render("index", &data));
let rendered = handlebars.render("index", &data)?;
let filename = Path::new(&ch.path).with_extension("html");
@ -106,24 +109,26 @@ impl Renderer for HtmlHandlebars {
// Write to file
info!("[*] Creating {:?} ✓", filename.display());
try!(book.write_file(filename, &rendered.into_bytes()));
book.write_file(filename, &rendered.into_bytes())?;
// Create an index.html from the first element in SUMMARY.md
if index {
debug!("[*]: index.html");
let mut content = String::new();
let _source = try!(File::open(book.get_dest().join(&ch.path.with_extension("html"))))
let _source = File::open(book.get_dest().join(&ch.path.with_extension("html")))?
.read_to_string(&mut content);
// This could cause a problem when someone displays code containing <base href=...>
// This could cause a problem when someone displays
// code containing <base href=...>
// on the front page, however this case should be very very rare...
content = content.lines()
content = content
.lines()
.filter(|line| !line.contains("<base href="))
.collect::<Vec<&str>>()
.join("\n");
try!(book.write_file("index.html", content.as_bytes()));
book.write_file("index.html", content.as_bytes())?;
info!("[*] Creating index.html from {:?} ✓",
book.get_dest().join(&ch.path.with_extension("html")));
@ -145,7 +150,7 @@ impl Renderer for HtmlHandlebars {
// Render the handlebars template with the data
debug!("[*]: Render template");
let rendered = try!(handlebars.render("index", &data));
let rendered = handlebars.render("index", &data)?;
// do several kinds of post-processing
let rendered = build_header_links(rendered, "print.html");
@ -153,29 +158,29 @@ impl Renderer for HtmlHandlebars {
let rendered = fix_code_blocks(rendered);
let rendered = add_playpen_pre(rendered);
try!(book.write_file(Path::new("print").with_extension("html"), &rendered.into_bytes()));
book.write_file(Path::new("print").with_extension("html"), &rendered.into_bytes())?;
info!("[*] Creating print.html ✓");
// Copy static files (js, css, images, ...)
debug!("[*] Copy static files");
try!(book.write_file("book.js", &theme.js));
try!(book.write_file("book.css", &theme.css));
try!(book.write_file("favicon.png", &theme.favicon));
try!(book.write_file("jquery.js", &theme.jquery));
try!(book.write_file("highlight.css", &theme.highlight_css));
try!(book.write_file("tomorrow-night.css", &theme.tomorrow_night_css));
try!(book.write_file("highlight.js", &theme.highlight_js));
try!(book.write_file("_FontAwesome/css/font-awesome.css", theme::FONT_AWESOME));
try!(book.write_file("_FontAwesome/fonts/fontawesome-webfont.eot", theme::FONT_AWESOME_EOT));
try!(book.write_file("_FontAwesome/fonts/fontawesome-webfont.svg", theme::FONT_AWESOME_SVG));
try!(book.write_file("_FontAwesome/fonts/fontawesome-webfont.ttf", theme::FONT_AWESOME_TTF));
try!(book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff", theme::FONT_AWESOME_WOFF));
try!(book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff2", theme::FONT_AWESOME_WOFF2));
try!(book.write_file("_FontAwesome/fonts/FontAwesome.ttf", theme::FONT_AWESOME_TTF));
book.write_file("book.js", &theme.js)?;
book.write_file("book.css", &theme.css)?;
book.write_file("favicon.png", &theme.favicon)?;
book.write_file("jquery.js", &theme.jquery)?;
book.write_file("highlight.css", &theme.highlight_css)?;
book.write_file("tomorrow-night.css", &theme.tomorrow_night_css)?;
book.write_file("highlight.js", &theme.highlight_js)?;
book.write_file("_FontAwesome/css/font-awesome.css", theme::FONT_AWESOME)?;
book.write_file("_FontAwesome/fonts/fontawesome-webfont.eot", theme::FONT_AWESOME_EOT)?;
book.write_file("_FontAwesome/fonts/fontawesome-webfont.svg", theme::FONT_AWESOME_SVG)?;
book.write_file("_FontAwesome/fonts/fontawesome-webfont.ttf", theme::FONT_AWESOME_TTF)?;
book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff", theme::FONT_AWESOME_WOFF)?;
book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff2", theme::FONT_AWESOME_WOFF2)?;
book.write_file("_FontAwesome/fonts/FontAwesome.ttf", theme::FONT_AWESOME_TTF)?;
// Copy all remaining files
try!(utils::fs::copy_files_except_ext(book.get_src(), book.get_dest(), true, &["md"]));
utils::fs::copy_files_except_ext(book.get_src(), book.get_dest(), true, &["md"])?;
Ok(())
}
@ -207,15 +212,17 @@ fn make_data(book: &MDBook) -> Result<serde_json::Map<String, serde_json::Value>
match *item {
BookItem::Affix(ref ch) => {
chapter.insert("name".to_owned(), json!(ch.name));
let path = ch.path.to_str().ok_or_else(||
io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))?;
let path = ch.path
.to_str()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))?;
chapter.insert("path".to_owned(), json!(path));
},
BookItem::Chapter(ref s, ref ch) => {
chapter.insert("section".to_owned(), json!(s));
chapter.insert("name".to_owned(), json!(ch.name));
let path = ch.path.to_str().ok_or_else(||
io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))?;
let path = ch.path
.to_str()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))?;
chapter.insert("path".to_owned(), json!(path));
},
BookItem::Spacer => {
@ -237,18 +244,27 @@ fn build_header_links(html: String, filename: &str) -> String {
let regex = Regex::new(r"<h(\d)>(.*?)</h\d>").unwrap();
let mut id_counter = HashMap::new();
regex.replace_all(&html, |caps: &Captures| {
regex
.replace_all(&html, |caps: &Captures| {
let level = &caps[1];
let text = &caps[2];
let mut id = text.to_string();
let repl_sub = vec!["<em>", "</em>", "<code>", "</code>",
"<strong>", "</strong>",
"&lt;", "&gt;", "&amp;", "&#39;", "&quot;"];
let repl_sub = vec!["<em>",
"</em>",
"<code>",
"</code>",
"<strong>",
"</strong>",
"&lt;",
"&gt;",
"&amp;",
"&#39;",
"&quot;"];
for sub in repl_sub {
id = id.replace(sub, "");
}
let id = id.chars().filter_map(|c| {
if c.is_alphanumeric() || c == '-' || c == '_' {
let id = id.chars()
.filter_map(|c| if c.is_alphanumeric() || c == '-' || c == '_' {
if c.is_ascii() {
Some(c.to_ascii_lowercase())
} else {
@ -258,8 +274,8 @@ fn build_header_links(html: String, filename: &str) -> String {
Some('-')
} else {
None
}
}).collect::<String>();
})
.collect::<String>();
let id_count = *id_counter.get(&id).unwrap_or(&0);
id_counter.insert(id.clone(), id_count + 1);
@ -271,8 +287,12 @@ fn build_header_links(html: String, filename: &str) -> String {
};
format!("<a class=\"header\" href=\"{filename}#{id}\" id=\"{id}\"><h{level}>{text}</h{level}></a>",
level=level, id=id, text=text, filename=filename)
}).into_owned()
level = level,
id = id,
text = text,
filename = filename)
})
.into_owned()
}
// anchors to the same page (href="#anchor") do not work because of
@ -280,18 +300,24 @@ fn build_header_links(html: String, filename: &str) -> String {
// that in a very inelegant way
fn fix_anchor_links(html: String, filename: &str) -> String {
let regex = Regex::new(r##"<a([^>]+)href="#([^"]+)"([^>]*)>"##).unwrap();
regex.replace_all(&html, |caps: &Captures| {
regex
.replace_all(&html, |caps: &Captures| {
let before = &caps[1];
let anchor = &caps[2];
let after = &caps[3];
format!("<a{before}href=\"{filename}#{anchor}\"{after}>",
before=before, filename=filename, anchor=anchor, after=after)
}).into_owned()
before = before,
filename = filename,
anchor = anchor,
after = after)
})
.into_owned()
}
// The rust book uses annotations for rustdoc to test code snippets, like the following:
// The rust book uses annotations for rustdoc to test code snippets,
// like the following:
// ```rust,should_panic
// fn main() {
// // Code here
@ -300,18 +326,21 @@ fn fix_anchor_links(html: String, filename: &str) -> String {
// This function replaces all commas by spaces in the code block classes
fn fix_code_blocks(html: String) -> String {
let regex = Regex::new(r##"<code([^>]+)class="([^"]+)"([^>]*)>"##).unwrap();
regex.replace_all(&html, |caps: &Captures| {
regex
.replace_all(&html, |caps: &Captures| {
let before = &caps[1];
let classes = &caps[2].replace(",", " ");
let after = &caps[3];
format!("<code{before}class=\"{classes}\"{after}>", before=before, classes=classes, after=after)
}).into_owned()
format!("<code{before}class=\"{classes}\"{after}>", before = before, classes = classes, after = after)
})
.into_owned()
}
fn add_playpen_pre(html: String) -> String {
let regex = Regex::new(r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"##).unwrap();
regex.replace_all(&html, |caps: &Captures| {
regex
.replace_all(&html, |caps: &Captures| {
let text = &caps[1];
let classes = &caps[2];
let code = &caps[3];
@ -326,14 +355,19 @@ fn add_playpen_pre(html: String) -> String {
let (attrs, code) = partition_source(code);
format!("<pre class=\"playpen\"><code class=\"{}\"># #![allow(unused_variables)]
{}#fn main() {{
{}
#}}</code></pre>", classes, attrs, code)
\
{}
#}}</code></pre>",
classes,
attrs,
code)
}
} else {
// not language-rust, so no-op
format!("{}", text)
}
}).into_owned()
})
.into_owned()
}
fn partition_source(s: &str) -> (String, String) {
@ -343,8 +377,7 @@ fn partition_source(s: &str) -> (String, String) {
for line in s.lines() {
let trimline = line.trim();
let header = trimline.chars().all(|c| c.is_whitespace()) ||
trimline.starts_with("#![");
let header = trimline.chars().all(|c| c.is_whitespace()) || trimline.starts_with("#![");
if !header || after_header {
after_header = true;
after.push_str(line);

View File

@ -14,9 +14,12 @@ pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(
// get value from context data
// rc.get_path() is current json parent path, you should always use it like this
// param is the key of value you want to display
let chapters = rc.context().navigate(rc.get_path(), &VecDeque::new(), "chapters").to_owned();
let chapters = rc.context()
.navigate(rc.get_path(), &VecDeque::new(), "chapters")
.to_owned();
let current = rc.context().navigate(rc.get_path(), &VecDeque::new(), "path")
let current = rc.context()
.navigate(rc.get_path(), &VecDeque::new(), "path")
.to_string()
.replace("\"", "");
@ -84,7 +87,7 @@ pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(
match _h.template() {
Some(t) => {
*rc.context_mut() = updated_context;
try!(t.render(r, rc));
t.render(r, rc)?;
},
None => return Err(RenderError::new("Error with the handlebars template")),
}
@ -115,9 +118,12 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
// get value from context data
// rc.get_path() is current json parent path, you should always use it like this
// param is the key of value you want to display
let chapters = rc.context().navigate(rc.get_path(), &VecDeque::new(), "chapters").to_owned();
let chapters = rc.context()
.navigate(rc.get_path(), &VecDeque::new(), "chapters")
.to_owned();
let current = rc.context().navigate(rc.get_path(), &VecDeque::new(), "path")
let current = rc.context()
.navigate(rc.get_path(), &VecDeque::new(), "path")
.to_string()
.replace("\"", "");
@ -181,7 +187,7 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
match _h.template() {
Some(t) => {
*rc.context_mut() = updated_context;
try!(t.render(r, rc));
t.render(r, rc)?;
},
None => return Err(RenderError::new("Error with the handlebars template")),
}

View File

@ -4,8 +4,9 @@ use std::io::Read;
pub fn render_playpen(s: &str, path: &Path) -> String {
// When replacing one thing in a string by something with a different length, the indices
// after that will not correspond, we therefore have to store the difference to correct this
// When replacing one thing in a string by something with a different length,
// the indices after that will not correspond,
// we therefore have to store the difference to correct this
let mut previous_end_index = 0;
let mut replaced = String::new();
@ -35,13 +36,13 @@ pub fn render_playpen(s: &str, path: &Path) -> String {
continue;
};
let replacement = String::new() + "<pre><code class=\"language-rust\">" + &file_content +
"</code></pre>";
let replacement = String::new() + "<pre><code class=\"language-rust\">" + &file_content + "</code></pre>";
replaced.push_str(&s[previous_end_index..playpen.start_index]);
replaced.push_str(&replacement);
previous_end_index = playpen.end_index;
// println!("Playpen{{ {}, {}, {:?}, {} }}", playpen.start_index, playpen.end_index, playpen.rust_file,
// println!("Playpen{{ {}, {}, {:?}, {} }}", playpen.start_index,
// playpen.end_index, playpen.rust_file,
// playpen.editable);
}
@ -189,7 +190,11 @@ fn test_find_playpens_escaped_playpen() {
println!("\nOUTPUT: {:?}\n", find_playpens(s, Path::new("")));
assert!(find_playpens(s, Path::new("")) ==
vec![
Playpen{start_index: 39, end_index: 68, rust_file: PathBuf::from("file.rs"), editable: true, escaped: true},
]);
vec![Playpen {
start_index: 39,
end_index: 68,
rust_file: PathBuf::from("file.rs"),
editable: true,
escaped: true,
}]);
}

View File

@ -15,9 +15,14 @@ impl HelperDef for RenderToc {
// get value from context data
// rc.get_path() is current json parent path, you should always use it like this
// param is the key of value you want to display
let chapters = rc.context().navigate(rc.get_path(), &VecDeque::new(), "chapters").to_owned();
let current = rc.context().navigate(rc.get_path(), &VecDeque::new(), "path").to_string().replace("\"", "");
try!(rc.writer.write_all("<ul class=\"chapter\">".as_bytes()));
let chapters = rc.context()
.navigate(rc.get_path(), &VecDeque::new(), "chapters")
.to_owned();
let current = rc.context()
.navigate(rc.get_path(), &VecDeque::new(), "path")
.to_string()
.replace("\"", "");
rc.writer.write_all("<ul class=\"chapter\">".as_bytes())?;
// Decode json format
let decoded: Vec<BTreeMap<String, String>> = serde_json::from_str(&chapters.to_string()).unwrap();
@ -28,7 +33,8 @@ impl HelperDef for RenderToc {
// Spacer
if item.get("spacer").is_some() {
try!(rc.writer.write_all("<li class=\"spacer\"></li>".as_bytes()));
rc.writer
.write_all("<li class=\"spacer\"></li>".as_bytes())?;
continue;
}
@ -40,48 +46,47 @@ impl HelperDef for RenderToc {
if level > current_level {
while level > current_level {
try!(rc.writer.write_all("<li>".as_bytes()));
try!(rc.writer.write_all("<ul class=\"section\">".as_bytes()));
rc.writer.write_all("<li>".as_bytes())?;
rc.writer.write_all("<ul class=\"section\">".as_bytes())?;
current_level += 1;
}
try!(rc.writer.write_all("<li>".as_bytes()));
rc.writer.write_all("<li>".as_bytes())?;
} else if level < current_level {
while level < current_level {
try!(rc.writer.write_all("</ul>".as_bytes()));
try!(rc.writer.write_all("</li>".as_bytes()));
rc.writer.write_all("</ul>".as_bytes())?;
rc.writer.write_all("</li>".as_bytes())?;
current_level -= 1;
}
try!(rc.writer.write_all("<li>".as_bytes()));
rc.writer.write_all("<li>".as_bytes())?;
} else {
try!(rc.writer.write_all("<li".as_bytes()));
rc.writer.write_all("<li".as_bytes())?;
if item.get("section").is_none() {
try!(rc.writer.write_all(" class=\"affix\"".as_bytes()));
rc.writer.write_all(" class=\"affix\"".as_bytes())?;
}
try!(rc.writer.write_all(">".as_bytes()));
rc.writer.write_all(">".as_bytes())?;
}
// Link
let path_exists = if let Some(path) = item.get("path") {
if !path.is_empty() {
try!(rc.writer.write_all("<a href=\"".as_bytes()));
rc.writer.write_all("<a href=\"".as_bytes())?;
// Add link
try!(rc.writer.write_all(Path::new(item.get("path")
.expect("Error: path should be Some(_)"))
let tmp = Path::new(item.get("path").expect("Error: path should be Some(_)"))
.with_extension("html")
.to_str()
.unwrap()
// Hack for windows who tends to use `\` as separator instead of `/`
.replace("\\", "/")
.as_bytes()));
.replace("\\", "/");
try!(rc.writer.write_all("\"".as_bytes()));
// Add link
rc.writer.write_all(tmp.as_bytes())?;
rc.writer.write_all("\"".as_bytes())?;
if path == &current {
try!(rc.writer.write_all(" class=\"active\"".as_bytes()));
rc.writer.write_all(" class=\"active\"".as_bytes())?;
}
try!(rc.writer.write_all(">".as_bytes()));
rc.writer.write_all(">".as_bytes())?;
true
} else {
false
@ -92,23 +97,21 @@ impl HelperDef for RenderToc {
// Section does not necessarily exist
if let Some(section) = item.get("section") {
try!(rc.writer.write_all("<strong>".as_bytes()));
try!(rc.writer.write_all(section.as_bytes()));
try!(rc.writer.write_all("</strong> ".as_bytes()));
rc.writer.write_all("<strong>".as_bytes())?;
rc.writer.write_all(section.as_bytes())?;
rc.writer.write_all("</strong> ".as_bytes())?;
}
if let Some(name) = item.get("name") {
// Render only inline code blocks
// filter all events that are not inline code blocks
let parser = Parser::new(name).filter(|event| {
match *event {
let parser = Parser::new(name).filter(|event| match *event {
Event::Start(Tag::Code) |
Event::End(Tag::Code) |
Event::InlineHtml(_) |
Event::Text(_) => true,
_ => false,
}
});
// render markdown to html
@ -116,23 +119,23 @@ impl HelperDef for RenderToc {
html::push_html(&mut markdown_parsed_name, parser);
// write to the handlebars template
try!(rc.writer.write_all(markdown_parsed_name.as_bytes()));
rc.writer.write_all(markdown_parsed_name.as_bytes())?;
}
if path_exists {
try!(rc.writer.write_all("</a>".as_bytes()));
rc.writer.write_all("</a>".as_bytes())?;
}
try!(rc.writer.write_all("</li>".as_bytes()));
rc.writer.write_all("</li>".as_bytes())?;
}
while current_level > 1 {
try!(rc.writer.write_all("</ul>".as_bytes()));
try!(rc.writer.write_all("</li>".as_bytes()));
rc.writer.write_all("</ul>".as_bytes())?;
rc.writer.write_all("</li>".as_bytes())?;
current_level -= 1;
}
try!(rc.writer.write_all("</ul>".as_bytes()));
rc.writer.write_all("</ul>".as_bytes())?;
Ok(())
}
}

View File

@ -19,11 +19,14 @@ pub static FONT_AWESOME_WOFF: &'static [u8] = include_bytes!("_FontAwesome/fonts
pub static FONT_AWESOME_WOFF2: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff2");
pub static FONT_AWESOME_OTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/FontAwesome.otf");
/// The `Theme` struct should be used instead of the static variables because the `new()` method
/// will look if the user has a theme directory in his source folder and use the users theme instead
/// The `Theme` struct should be used instead of the static variables because
/// the `new()` method
/// will look if the user has a theme directory in his source folder and use
/// the users theme instead
/// of the default.
///
/// You should exceptionnaly use the static variables only if you need the default theme even if the
/// You should exceptionnaly use the static variables only if you need the
/// default theme even if the
/// user has specified another theme.
pub struct Theme {
pub index: Vec<u8>,

View File

@ -24,10 +24,11 @@ pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> {
Ok(content)
}
/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
/// Takes a path and returns a path containing just enough `../` to point to
/// the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
/// This is mostly interesting for a relative path to point back to the
/// directory from where the path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
@ -41,9 +42,10 @@ pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> {
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.
/// **note:** it's not very fool-proof, if you find a situation where
/// it doesn't return the correct path.
/// Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues)
/// or a [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.
pub fn path_to_root(path: &Path) -> String {
debug!("[fn]: path_to_root");
@ -66,8 +68,9 @@ pub fn path_to_root(path: &Path) -> String {
/// 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.
/// 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.
pub fn create_file(path: &Path) -> io::Result<File> {
debug!("[fn]: create_file");
@ -76,7 +79,7 @@ pub fn create_file(path: &Path) -> io::Result<File> {
if let Some(p) = path.parent() {
debug!("Parent directory is: {:?}", p);
try!(fs::create_dir_all(p));
fs::create_dir_all(p)?;
}
debug!("[*]: Create file: {:?}", path);
@ -86,13 +89,13 @@ pub fn create_file(path: &Path) -> io::Result<File> {
/// Removes all the content of a directory but not the directory itself
pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
for item in try!(fs::read_dir(dir)) {
for item in fs::read_dir(dir)? {
if let Ok(item) = item {
let item = item.path();
if item.is_dir() {
try!(fs::remove_dir_all(item));
fs::remove_dir_all(item)?;
} else {
try!(fs::remove_file(item));
fs::remove_file(item)?;
}
}
}
@ -101,20 +104,21 @@ pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
///
///
/// Copies all files of a directory to another one except the files with the extensions given in the
/// `ext_blacklist` array
/// Copies all files of a directory to another one except the files
/// with the extensions given in the `ext_blacklist` array
pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box<Error>> {
pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str])
-> Result<(), Box<Error>> {
debug!("[fn] copy_files_except_ext");
// Check that from and to are different
if from == to {
return Ok(());
}
debug!("[*] Loop");
for entry in try!(fs::read_dir(from)) {
let entry = try!(entry);
for entry in fs::read_dir(from)? {
let entry = entry?;
debug!("[*] {:?}", entry.path());
let metadata = try!(entry.metadata());
let metadata = entry.metadata()?;
// If the entry is a dir and the recursive option is enabled, call itself
if metadata.is_dir() && recursive {
@ -125,13 +129,10 @@ pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blackl
// check if output dir already exists
if !to.join(entry.file_name()).exists() {
try!(fs::create_dir(&to.join(entry.file_name())));
fs::create_dir(&to.join(entry.file_name()))?;
}
try!(copy_files_except_ext(&from.join(entry.file_name()),
&to.join(entry.file_name()),
true,
ext_blacklist));
copy_files_except_ext(&from.join(entry.file_name()), &to.join(entry.file_name()), true, ext_blacklist)?;
} else if metadata.is_file() {
// Check if it is in the blacklist
@ -141,13 +142,22 @@ pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blackl
}
}
debug!("[*] creating path for file: {:?}",
&to.join(entry.path().file_name().expect("a file should have a file name...")));
&to.join(entry
.path()
.file_name()
.expect("a file should have a file name...")));
info!("[*] Copying file: {:?}\n to {:?}",
entry.path(),
&to.join(entry.path().file_name().expect("a file should have a file name...")));
try!(fs::copy(entry.path(),
&to.join(entry.path().file_name().expect("a file should have a file name..."))));
&to.join(entry
.path()
.file_name()
.expect("a file should have a file name...")));
fs::copy(entry.path(),
&to.join(entry
.path()
.file_name()
.expect("a file should have a file name...")))?;
}
}
Ok(())