1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Implementation of the `build` subcommand, used to compile a book.
14 use std
::fs
::{self, File}
;
15 use std
::io
::prelude
::*;
16 use std
::io
::{self, BufWriter}
;
17 use std
::path
::{Path, PathBuf}
;
18 use rustc_back
::tempdir
::TempDir
;
20 use subcommand
::Subcommand
;
22 use error
::{err, CliResult, CommandResult}
;
24 use book
::{Book, BookItem}
;
32 pub fn parse_cmd(name
: &str) -> Option
<Box
<Subcommand
>> {
40 fn write_toc(book
: &Book
, current_page
: &BookItem
, out
: &mut Write
) -> io
::Result
<()> {
41 fn walk_items(items
: &[BookItem
],
43 current_page
: &BookItem
,
44 out
: &mut Write
) -> io
::Result
<()> {
45 for (i
, item
) in items
.iter().enumerate() {
46 try
!(walk_item(item
, &format
!("{}{}.", section
, i
+ 1)[..], current_page
, out
));
50 fn walk_item(item
: &BookItem
,
52 current_page
: &BookItem
,
53 out
: &mut Write
) -> io
::Result
<()> {
54 let class_string
= if item
.path
== current_page
.path
{
60 try
!(writeln
!(out
, "<li><a {} href='{}'><b>{}</b> {}</a>",
62 current_page
.path_to_root
.join(&item
.path
).with_extension("html").display(),
65 if !item
.children
.is_empty() {
66 try
!(writeln
!(out
, "<ul class='section'>"));
67 let _
= walk_items(&item
.children
[..], section
, current_page
, out
);
68 try
!(writeln
!(out
, "</ul>"));
70 try
!(writeln
!(out
, "</li>"));
75 try
!(writeln
!(out
, "<div id='toc' class='mobile-hidden'>"));
76 try
!(writeln
!(out
, "<ul class='chapter'>"));
77 try
!(walk_items(&book
.chapters
[..], "", ¤t_page
, out
));
78 try
!(writeln
!(out
, "</ul>"));
79 try
!(writeln
!(out
, "</div>"));
84 fn render(book
: &Book
, tgt
: &Path
) -> CliResult
<()> {
85 let tmp
= try
!(TempDir
::new("rust-book"));
87 for (_section
, item
) in book
.iter() {
88 let out_path
= match item
.path
.parent() {
89 Some(p
) => tgt
.join(p
),
90 None
=> tgt
.to_path_buf(),
94 if env
::args().len() < 3 {
95 src
= env
::current_dir().unwrap().clone();
97 src
= PathBuf
::from(&env
::args().nth(2).unwrap());
99 // preprocess the markdown, rerouting markdown references to html
101 let mut markdown_data
= String
::new();
102 try
!(File
::open(&src
.join(&item
.path
)).and_then(|mut f
| {
103 f
.read_to_string(&mut markdown_data
)
105 let preprocessed_path
= tmp
.path().join(item
.path
.file_name().unwrap());
107 let urls
= markdown_data
.replace(".md)", ".html)");
108 try
!(File
::create(&preprocessed_path
).and_then(|mut f
| {
109 f
.write_all(urls
.as_bytes())
113 // write the prelude to a temporary HTML file for rustdoc inclusion
114 let prelude
= tmp
.path().join("prelude.html");
116 let mut toc
= BufWriter
::new(try
!(File
::create(&prelude
)));
117 try
!(writeln
!(&mut toc
, r
#"<div id="nav">
118 <button id="toggle-nav">
119 <span class="sr-only">Toggle navigation</span>
120 <span class="bar"></span>
121 <span class="bar"></span>
122 <span class="bar"></span>
125 let _
= write_toc(book
, &item
, &mut toc
);
126 try
!(writeln
!(&mut toc
, "<div id='page-wrapper'>"));
127 try
!(writeln
!(&mut toc
, "<div id='page'>"));
130 // write the postlude to a temporary HTML file for rustdoc inclusion
131 let postlude
= tmp
.path().join("postlude.html");
133 let mut toc
= BufWriter
::new(try
!(File
::create(&postlude
)));
134 try
!(toc
.write_all(javascript
::JAVASCRIPT
.as_bytes()));
135 try
!(writeln
!(&mut toc
, "</div></div>"));
138 try
!(fs
::create_dir_all(&out_path
));
140 let rustdoc_args
: &[String
] = &[
142 preprocessed_path
.display().to_string(),
143 format
!("-o{}", out_path
.display()),
144 format
!("--html-before-content={}", prelude
.display()),
145 format
!("--html-after-content={}", postlude
.display()),
146 format
!("--markdown-playground-url=http://play.rust-lang.org"),
147 format
!("--markdown-css={}", item
.path_to_root
.join("rust-book.css").display()),
148 "--markdown-no-toc".to_string(),
150 let output_result
= rustdoc
::main_args(rustdoc_args
);
151 if output_result
!= 0 {
152 let message
= format
!("Could not execute `rustdoc` with {:?}: {}",
153 rustdoc_args
, output_result
);
154 return Err(err(&message
));
158 // create index.html from the root README
159 try
!(fs
::copy(&tgt
.join("README.html"), &tgt
.join("index.html")));
161 // Copy js for playpen
162 let mut playpen
= try
!(File
::create(tgt
.join("playpen.js")));
163 let js
= include_bytes
!("../librustdoc/html/static/playpen.js");
164 try
!(playpen
.write_all(js
));
168 impl Subcommand
for Build
{
169 fn parse_args(&mut self, _
: &[String
]) -> CliResult
<()> {
173 fn execute(&mut self, term
: &mut Term
) -> CommandResult
<()> {
174 let cwd
= env
::current_dir().unwrap();
178 if env
::args().len() < 3 {
181 src
= PathBuf
::from(&env
::args().nth(2).unwrap());
184 if env
::args().len() < 4 {
185 tgt
= cwd
.join("_book");
187 tgt
= PathBuf
::from(&env
::args().nth(3).unwrap());
190 // `_book` directory may already exist from previous runs. Check and
191 // delete it if it exists.
192 for entry
in try
!(fs
::read_dir(&cwd
)) {
193 let path
= try
!(entry
).path();
194 if path
== tgt { try!(fs::remove_dir_all(&tgt)) }
196 try
!(fs
::create_dir(&tgt
));
199 let css
= include_bytes
!("static/rustbook.css");
200 let js
= include_bytes
!("static/rustbook.js");
202 let mut css_file
= try
!(File
::create(tgt
.join("rust-book.css")));
203 try
!(css_file
.write_all(css
));
205 let mut js_file
= try
!(File
::create(tgt
.join("rust-book.js")));
206 try
!(js_file
.write_all(js
));
209 let mut summary
= try
!(File
::open(&src
.join("SUMMARY.md")));
210 match book
::parse_summary(&mut summary
, &src
) {
212 // execute rustdoc on the whole book
216 let n
= errors
.len();
218 term
.err(&format
!("error: {}", err
)[..]);
221 Err(err(&format
!("{} errors occurred", n
)))