1 // Copyright 2014 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
, path_to_root
: &Path
, out
: &mut Write
) -> io
::Result
<()> {
41 fn walk_items(items
: &[BookItem
],
44 out
: &mut Write
) -> io
::Result
<()> {
45 for (i
, item
) in items
.iter().enumerate() {
46 try
!(walk_item(item
, &format
!("{}{}.", section
, i
+ 1)[..], path_to_root
, out
));
50 fn walk_item(item
: &BookItem
,
53 out
: &mut Write
) -> io
::Result
<()> {
54 try
!(writeln
!(out
, "<li><a href='{}'><b>{}</b> {}</a>",
55 path_to_root
.join(&item
.path
.with_extension("html")).display(),
58 if !item
.children
.is_empty() {
59 try
!(writeln
!(out
, "<ul class='section'>"));
60 let _
= walk_items(&item
.children
[..], section
, path_to_root
, out
);
61 try
!(writeln
!(out
, "</ul>"));
63 try
!(writeln
!(out
, "</li>"));
68 try
!(writeln
!(out
, "<div id='toc' class='mobile-hidden'>"));
69 try
!(writeln
!(out
, "<ul class='chapter'>"));
70 try
!(walk_items(&book
.chapters
[..], "", path_to_root
, out
));
71 try
!(writeln
!(out
, "</ul>"));
72 try
!(writeln
!(out
, "</div>"));
77 fn render(book
: &Book
, tgt
: &Path
) -> CliResult
<()> {
78 let tmp
= try
!(TempDir
::new("rust-book"));
80 for (_section
, item
) in book
.iter() {
81 let out_path
= match item
.path
.parent() {
82 Some(p
) => tgt
.join(p
),
83 None
=> tgt
.to_path_buf(),
87 if env
::args().len() < 3 {
88 src
= env
::current_dir().unwrap().clone();
90 src
= PathBuf
::from(&env
::args().nth(2).unwrap());
92 // preprocess the markdown, rerouting markdown references to html
94 let mut markdown_data
= String
::new();
95 try
!(File
::open(&src
.join(&item
.path
)).and_then(|mut f
| {
96 f
.read_to_string(&mut markdown_data
)
98 let preprocessed_path
= tmp
.path().join(item
.path
.file_name().unwrap());
100 let urls
= markdown_data
.replace(".md)", ".html)");
101 try
!(File
::create(&preprocessed_path
).and_then(|mut f
| {
102 f
.write_all(urls
.as_bytes())
106 // write the prelude to a temporary HTML file for rustdoc inclusion
107 let prelude
= tmp
.path().join("prelude.html");
109 let mut toc
= BufWriter
::new(try
!(File
::create(&prelude
)));
110 try
!(writeln
!(&mut toc
, r
#"<div id="nav">
111 <button id="toggle-nav">
112 <span class="sr-only">Toggle navigation</span>
113 <span class="bar"></span>
114 <span class="bar"></span>
115 <span class="bar"></span>
118 let _
= write_toc(book
, &item
.path_to_root
, &mut toc
);
119 try
!(writeln
!(&mut toc
, "<div id='page-wrapper'>"));
120 try
!(writeln
!(&mut toc
, "<div id='page'>"));
123 // write the postlude to a temporary HTML file for rustdoc inclusion
124 let postlude
= tmp
.path().join("postlude.html");
126 let mut toc
= BufWriter
::new(try
!(File
::create(&postlude
)));
127 try
!(toc
.write_all(javascript
::JAVASCRIPT
.as_bytes()));
128 try
!(writeln
!(&mut toc
, "</div></div>"));
131 try
!(fs
::create_dir_all(&out_path
));
133 let rustdoc_args
: &[String
] = &[
135 preprocessed_path
.display().to_string(),
136 format
!("-o{}", out_path
.display()),
137 format
!("--html-before-content={}", prelude
.display()),
138 format
!("--html-after-content={}", postlude
.display()),
139 format
!("--markdown-playground-url=http://play.rust-lang.org"),
140 format
!("--markdown-css={}", item
.path_to_root
.join("rust-book.css").display()),
141 "--markdown-no-toc".to_string(),
143 let output_result
= rustdoc
::main_args(rustdoc_args
);
144 if output_result
!= 0 {
145 let message
= format
!("Could not execute `rustdoc` with {:?}: {}",
146 rustdoc_args
, output_result
);
147 return Err(err(&message
));
151 // create index.html from the root README
152 try
!(fs
::copy(&tgt
.join("README.html"), &tgt
.join("index.html")));
154 // Copy some js for playpen
155 let mut jquery
= try
!(File
::create(tgt
.join("jquery.js")));
156 let js
= include_bytes
!("../librustdoc/html/static/jquery-2.1.0.min.js");
157 try
!(jquery
.write_all(js
));
158 let mut playpen
= try
!(File
::create(tgt
.join("playpen.js")));
159 let js
= include_bytes
!("../librustdoc/html/static/playpen.js");
160 try
!(playpen
.write_all(js
));
164 impl Subcommand
for Build
{
165 fn parse_args(&mut self, _
: &[String
]) -> CliResult
<()> {
169 fn execute(&mut self, term
: &mut Term
) -> CommandResult
<()> {
170 let cwd
= env
::current_dir().unwrap();
174 if env
::args().len() < 3 {
177 src
= PathBuf
::from(&env
::args().nth(2).unwrap());
180 if env
::args().len() < 4 {
181 tgt
= cwd
.join("_book");
183 tgt
= PathBuf
::from(&env
::args().nth(3).unwrap());
186 try
!(fs
::create_dir(&tgt
));
188 try
!(File
::create(&tgt
.join("rust-book.css")).and_then(|mut f
| {
189 f
.write_all(css
::STYLE
.as_bytes())
192 let mut summary
= try
!(File
::open(&src
.join("SUMMARY.md")));
193 match book
::parse_summary(&mut summary
, &src
) {
195 // execute rustdoc on the whole book
199 let n
= errors
.len();
201 term
.err(&format
!("error: {}", err
)[..]);
204 Err(err(&format
!("{} errors occurred", n
)))