rust/src/rustbook/build.rs
Alex Crichton 6c29708bf9 regex: Remove in-tree version
The regex library was largely used for non-critical aspects of the compiler and
various external tooling. The library at this point is duplicated with its
out-of-tree counterpart and as such imposes a bit of a maintenance overhead as
well as compile time hit for the compiler itself.

The last major user of the regex library is the libtest library, using regexes
for filters when running tests. This removal means that the filtering has gone
back to substring matching rather than using regexes.
2015-01-23 21:04:10 -08:00

189 lines
6.3 KiB
Rust

// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation of the `build` subcommand, used to compile a book.
use std::os;
use std::io;
use std::io::{fs, File, BufferedWriter, TempDir, IoResult};
use subcommand::Subcommand;
use term::Term;
use error::{Error, CliResult, CommandResult};
use book;
use book::{Book, BookItem};
use css;
use javascript;
use rustdoc;
struct Build;
pub fn parse_cmd(name: &str) -> Option<Box<Subcommand>> {
if name == "build" {
Some(box Build as Box<Subcommand>)
} else {
None
}
}
fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()> {
fn walk_items(items: &[BookItem],
section: &str,
path_to_root: &Path,
out: &mut Writer) -> IoResult<()> {
for (i, item) in items.iter().enumerate() {
try!(walk_item(item, &format!("{}{}.", section, i + 1)[], path_to_root, out));
}
Ok(())
}
fn walk_item(item: &BookItem,
section: &str,
path_to_root: &Path,
out: &mut Writer) -> IoResult<()> {
try!(writeln!(out, "<li><a href='{}'><b>{}</b> {}</a>",
path_to_root.join(item.path.with_extension("html")).display(),
section,
item.title));
if !item.children.is_empty() {
try!(writeln!(out, "<ul class='section'>"));
let _ = walk_items(&item.children[], section, path_to_root, out);
try!(writeln!(out, "</ul>"));
}
try!(writeln!(out, "</li>"));
Ok(())
}
try!(writeln!(out, "<div id='toc' class='mobile-hidden'>"));
try!(writeln!(out, "<ul class='chapter'>"));
try!(walk_items(&book.chapters[], "", path_to_root, out));
try!(writeln!(out, "</ul>"));
try!(writeln!(out, "</div>"));
Ok(())
}
fn render(book: &Book, tgt: &Path) -> CliResult<()> {
let tmp = try!(TempDir::new("rust-book"));
for (section, item) in book.iter() {
println!("{} {}", section, item.title);
let out_path = tgt.join(item.path.dirname());
let src;
if os::args().len() < 3 {
src = os::getcwd().unwrap().clone();
} else {
src = Path::new(os::args()[2].clone());
}
// preprocess the markdown, rerouting markdown references to html references
let markdown_data = try!(File::open(&src.join(&item.path)).read_to_string());
let preprocessed_path = tmp.path().join(item.path.filename().unwrap());
{
let urls = markdown_data.replace(".md)", ".html)");
try!(File::create(&preprocessed_path)
.write_str(&urls[]));
}
// write the prelude to a temporary HTML file for rustdoc inclusion
let prelude = tmp.path().join("prelude.html");
{
let mut toc = BufferedWriter::new(try!(File::create(&prelude)));
try!(writeln!(&mut toc, r#"<div id="nav">
<button id="toggle-nav">
<span class="sr-only">Toggle navigation</span>
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
</div>"#));
let _ = write_toc(book, &item.path_to_root, &mut toc);
try!(writeln!(&mut toc, "<div id='page-wrapper'>"));
try!(writeln!(&mut toc, "<div id='page'>"));
}
// write the postlude to a temporary HTML file for rustdoc inclusion
let postlude = tmp.path().join("postlude.html");
{
let mut toc = BufferedWriter::new(try!(File::create(&postlude)));
try!(toc.write_str(javascript::JAVASCRIPT));
try!(writeln!(&mut toc, "</div></div>"));
}
try!(fs::mkdir_recursive(&out_path, io::USER_DIR));
let rustdoc_args: &[String] = &[
"".to_string(),
preprocessed_path.display().to_string(),
format!("-o{}", out_path.display()),
format!("--html-before-content={}", prelude.display()),
format!("--html-after-content={}", postlude.display()),
format!("--markdown-css={}", item.path_to_root.join("rust-book.css").display()),
"--markdown-no-toc".to_string(),
];
let output_result = rustdoc::main_args(rustdoc_args);
if output_result != 0 {
let message = format!("Could not execute `rustdoc` with {:?}: {}",
rustdoc_args, output_result);
return Err(box message as Box<Error>);
}
}
// create index.html from the root README
try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html")));
Ok(())
}
impl Subcommand for Build {
fn parse_args(&mut self, _: &[String]) -> CliResult<()> {
Ok(())
}
fn usage(&self) {}
fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
let cwd = os::getcwd().unwrap();
let src;
let tgt;
if os::args().len() < 3 {
src = cwd.clone();
} else {
src = Path::new(os::args()[2].clone());
}
if os::args().len() < 4 {
tgt = cwd.join("_book");
} else {
tgt = Path::new(os::args()[3].clone());
}
try!(fs::mkdir(&tgt, io::USER_DIR));
try!(File::create(&tgt.join("rust-book.css")).write_str(css::STYLE));
let summary = try!(File::open(&src.join("SUMMARY.md")));
match book::parse_summary(summary, &src) {
Ok(book) => {
// execute rustdoc on the whole book
render(&book, &tgt)
}
Err(errors) => {
let n = errors.len();
for err in errors.into_iter() {
term.err(&format!("error: {}", err)[]);
}
Err(box format!("{} errors occurred", n) as Box<Error>)
}
}
}
}