Re-implement rustbook in terms of mdbook
mdbook has a lot of optional dependencies that we don't want, so instead of using it directly, we re-build rustbook to use mdbook as a library. For convenience' sake, we keep the same CLI interface as mdbook; the only difference is that it only accepts build and test subcommands, rather than the full range.
This commit is contained in:
parent
717ac960b5
commit
a076961fd0
19 changed files with 311 additions and 972 deletions
216
src/Cargo.lock
generated
216
src/Cargo.lock
generated
|
@ -6,6 +6,14 @@ dependencies = [
|
|||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc"
|
||||
version = "0.0.0"
|
||||
|
@ -31,10 +39,25 @@ dependencies = [
|
|||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "arena"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
|
@ -69,6 +92,21 @@ dependencies = [
|
|||
name = "cargotest"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.19.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.18"
|
||||
|
@ -114,6 +152,7 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -158,6 +197,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
name = "graphviz"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.0.0"
|
||||
|
@ -183,6 +249,27 @@ name = "log"
|
|||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"handlebars 0.20.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "0.2.13"
|
||||
|
@ -209,6 +296,11 @@ dependencies = [
|
|||
"unwind 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc_macro"
|
||||
version = "0.0.0"
|
||||
|
@ -225,6 +317,15 @@ dependencies = [
|
|||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qemu-test-client"
|
||||
version = "0.1.0"
|
||||
|
@ -233,6 +334,11 @@ version = "0.1.0"
|
|||
name = "qemu-test-server"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.0.0"
|
||||
|
@ -240,9 +346,30 @@ dependencies = [
|
|||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustbook"
|
||||
version = "0.0.0"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mdbook 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc"
|
||||
|
@ -650,6 +777,11 @@ dependencies = [
|
|||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syntax"
|
||||
version = "0.0.0"
|
||||
|
@ -685,6 +817,16 @@ dependencies = [
|
|||
name = "term"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test"
|
||||
version = "0.0.0"
|
||||
|
@ -700,6 +842,23 @@ dependencies = [
|
|||
"test 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tidy"
|
||||
version = "0.1.0"
|
||||
|
@ -712,14 +871,69 @@ dependencies = [
|
|||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95b78f3fe0fc94c13c731714363260e04b557a637166f33a4570d3189d642374"
|
||||
"checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
|
||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
||||
"checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d"
|
||||
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
|
||||
"checksum handlebars 0.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "07f9c1d28bcfb97143c95ed0667141677b2b5675c7ba3d5b81459ad43b1073bd"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
|
||||
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
|
||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||
"checksum mdbook 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "a629cd0194bbd0340a70db83a94b27cf9881fac8c55e6a2db983addcb7114ee4"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
|
||||
"checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
|
||||
"checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41"
|
||||
"checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
|
||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
|
||||
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"
|
||||
"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||
"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
|
||||
"checksum unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c3bc443ded17b11305ffffe6b37e2076f328a5a8cb6aa877b1b98f77699e98b5"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
|
|
@ -47,6 +47,7 @@ pub fn rustbook(build: &Build, target: &str, name: &str) {
|
|||
build.run(build.tool_cmd(&compiler, "rustbook")
|
||||
.arg("build")
|
||||
.arg(&src)
|
||||
.arg("-d")
|
||||
.arg(out));
|
||||
}
|
||||
|
||||
|
|
3
src/doc/book/src/SUMMARY.md
Normal file
3
src/doc/book/src/SUMMARY.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Summary
|
||||
|
||||
- [Chapter 1](./chapter_1.md)
|
1
src/doc/book/src/chapter_1.md
Normal file
1
src/doc/book/src/chapter_1.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Chapter 1
|
3
src/doc/nomicon/src/SUMMARY.md
Normal file
3
src/doc/nomicon/src/SUMMARY.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Summary
|
||||
|
||||
- [Chapter 1](./chapter_1.md)
|
1
src/doc/nomicon/src/chapter_1.md
Normal file
1
src/doc/nomicon/src/chapter_1.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Chapter 1
|
|
@ -1,9 +1,12 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustbook"
|
||||
version = "0.0.0"
|
||||
build = false
|
||||
version = "0.1.0"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[[bin]]
|
||||
name = "rustbook"
|
||||
path = "main.rs"
|
||||
[dependencies]
|
||||
clap = "2.19.3"
|
||||
|
||||
[dependencies.mdbook]
|
||||
version = "0.0.14"
|
||||
default-features = false
|
||||
|
|
|
@ -1,171 +0,0 @@
|
|||
// 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.
|
||||
|
||||
//! Basic data structures for representing a book.
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::iter;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct BookItem {
|
||||
pub title: String,
|
||||
pub path: PathBuf,
|
||||
pub path_to_root: PathBuf,
|
||||
pub children: Vec<BookItem>,
|
||||
}
|
||||
|
||||
pub struct Book {
|
||||
pub chapters: Vec<BookItem>,
|
||||
}
|
||||
|
||||
/// A depth-first iterator over a book.
|
||||
pub struct BookItems<'a> {
|
||||
cur_items: &'a [BookItem],
|
||||
cur_idx: usize,
|
||||
stack: Vec<(&'a [BookItem], usize)>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BookItems<'a> {
|
||||
type Item = (String, &'a BookItem);
|
||||
|
||||
fn next(&mut self) -> Option<(String, &'a BookItem)> {
|
||||
loop {
|
||||
if self.cur_idx >= self.cur_items.len() {
|
||||
match self.stack.pop() {
|
||||
None => return None,
|
||||
Some((parent_items, parent_idx)) => {
|
||||
self.cur_items = parent_items;
|
||||
self.cur_idx = parent_idx + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let cur = self.cur_items.get(self.cur_idx).unwrap();
|
||||
|
||||
let mut section = "".to_string();
|
||||
for &(_, idx) in &self.stack {
|
||||
section.push_str(&(idx + 1).to_string()[..]);
|
||||
section.push('.');
|
||||
}
|
||||
section.push_str(&(self.cur_idx + 1).to_string()[..]);
|
||||
section.push('.');
|
||||
|
||||
self.stack.push((self.cur_items, self.cur_idx));
|
||||
self.cur_items = &cur.children[..];
|
||||
self.cur_idx = 0;
|
||||
return Some((section, cur))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Book {
|
||||
pub fn iter(&self) -> BookItems {
|
||||
BookItems {
|
||||
cur_items: &self.chapters[..],
|
||||
cur_idx: 0,
|
||||
stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a book by parsing a summary (markdown table of contents).
|
||||
pub fn parse_summary(input: &mut Read, src: &Path) -> Result<Book, Vec<String>> {
|
||||
fn collapse(stack: &mut Vec<BookItem>,
|
||||
top_items: &mut Vec<BookItem>,
|
||||
to_level: usize) {
|
||||
loop {
|
||||
if stack.len() < to_level { return }
|
||||
if stack.len() == 1 {
|
||||
top_items.push(stack.pop().unwrap());
|
||||
return;
|
||||
}
|
||||
|
||||
let tip = stack.pop().unwrap();
|
||||
let last = stack.len() - 1;
|
||||
stack[last].children.push(tip);
|
||||
}
|
||||
}
|
||||
|
||||
let mut top_items = vec![];
|
||||
let mut stack = vec![];
|
||||
let mut errors = vec![];
|
||||
|
||||
// always include the introduction
|
||||
top_items.push(BookItem {
|
||||
title: "Introduction".to_string(),
|
||||
path: PathBuf::from("README.md"),
|
||||
path_to_root: PathBuf::from(""),
|
||||
children: vec![],
|
||||
});
|
||||
|
||||
for line_result in BufReader::new(input).lines() {
|
||||
let line = match line_result {
|
||||
Ok(line) => line,
|
||||
Err(err) => {
|
||||
errors.push(err.to_string());
|
||||
return Err(errors);
|
||||
}
|
||||
};
|
||||
|
||||
let star_idx = match line.find("*") { Some(i) => i, None => continue };
|
||||
|
||||
let start_bracket = star_idx + line[star_idx..].find("[").unwrap();
|
||||
let end_bracket = start_bracket + line[start_bracket..].find("](").unwrap();
|
||||
let start_paren = end_bracket + 1;
|
||||
let end_paren = start_paren + line[start_paren..].find(")").unwrap();
|
||||
|
||||
let given_path = &line[start_paren + 1 .. end_paren];
|
||||
let title = line[start_bracket + 1..end_bracket].to_string();
|
||||
let indent = &line[..star_idx];
|
||||
|
||||
let path_from_root = match src.join(given_path).strip_prefix(src) {
|
||||
Ok(p) => p.to_path_buf(),
|
||||
Err(..) => {
|
||||
errors.push(format!("paths in SUMMARY.md must be relative, \
|
||||
but path '{}' for section '{}' is not.",
|
||||
given_path, title));
|
||||
PathBuf::new()
|
||||
}
|
||||
};
|
||||
let path_to_root = PathBuf::from(&iter::repeat("../")
|
||||
.take(path_from_root.components().count() - 1)
|
||||
.collect::<String>());
|
||||
let item = BookItem {
|
||||
title: title,
|
||||
path: path_from_root,
|
||||
path_to_root: path_to_root,
|
||||
children: vec![],
|
||||
};
|
||||
let level = indent.chars().map(|c| -> usize {
|
||||
match c {
|
||||
' ' => 1,
|
||||
'\t' => 4,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}).sum::<usize>() / 4 + 1;
|
||||
|
||||
if level > stack.len() + 1 {
|
||||
errors.push(format!("section '{}' is indented too deeply; \
|
||||
found {}, expected {} or less",
|
||||
item.title, level, stack.len() + 1));
|
||||
} else if level <= stack.len() {
|
||||
collapse(&mut stack, &mut top_items, level);
|
||||
}
|
||||
stack.push(item)
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
collapse(&mut stack, &mut top_items, 1);
|
||||
Ok(Book { chapters: top_items })
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
// Copyright 2014-2015 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::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, BufWriter};
|
||||
use std::path::{Path, PathBuf};
|
||||
use rustc_back::tempdir::TempDir;
|
||||
|
||||
use subcommand::Subcommand;
|
||||
use term::Term;
|
||||
use error::{err, CliResult, CommandResult};
|
||||
use book;
|
||||
use book::{Book, BookItem};
|
||||
|
||||
use rustdoc;
|
||||
|
||||
struct Build;
|
||||
|
||||
pub fn parse_cmd(name: &str) -> Option<Box<Subcommand>> {
|
||||
if name == "build" {
|
||||
Some(Box::new(Build))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn write_toc(book: &Book, current_page: &BookItem, out: &mut Write) -> io::Result<()> {
|
||||
fn walk_items(items: &[BookItem],
|
||||
section: &str,
|
||||
current_page: &BookItem,
|
||||
out: &mut Write) -> io::Result<()> {
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
walk_item(item, &format!("{}{}.", section, i + 1)[..], current_page, out)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn walk_item(item: &BookItem,
|
||||
section: &str,
|
||||
current_page: &BookItem,
|
||||
out: &mut Write) -> io::Result<()> {
|
||||
let class_string = if item.path == current_page.path {
|
||||
"class='active'"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
writeln!(out, "<li><a {} href='{}'><b>{}</b> {}</a>",
|
||||
class_string,
|
||||
current_page.path_to_root.join(&item.path).with_extension("html").display(),
|
||||
section,
|
||||
item.title)?;
|
||||
if !item.children.is_empty() {
|
||||
writeln!(out, "<ol class='section'>")?;
|
||||
let _ = walk_items(&item.children[..], section, current_page, out);
|
||||
writeln!(out, "</ol>")?;
|
||||
}
|
||||
writeln!(out, "</li>")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
writeln!(out, "<div id='toc' class='mobile-hidden'>")?;
|
||||
writeln!(out, "<ol class='chapter'>")?;
|
||||
walk_items(&book.chapters[..], "", ¤t_page, out)?;
|
||||
writeln!(out, "</ol>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
||||
let tmp = TempDir::new("rustbook")?;
|
||||
|
||||
for (_section, item) in book.iter() {
|
||||
let out_path = match item.path.parent() {
|
||||
Some(p) => tgt.join(p),
|
||||
None => tgt.to_path_buf(),
|
||||
};
|
||||
|
||||
let src;
|
||||
if env::args().len() < 3 {
|
||||
src = env::current_dir().unwrap().clone();
|
||||
} else {
|
||||
src = PathBuf::from(&env::args().nth(2).unwrap());
|
||||
}
|
||||
// preprocess the markdown, rerouting markdown references to html
|
||||
// references
|
||||
let mut markdown_data = String::new();
|
||||
File::open(&src.join(&item.path)).and_then(|mut f| {
|
||||
f.read_to_string(&mut markdown_data)
|
||||
})?;
|
||||
let preprocessed_path = tmp.path().join(item.path.file_name().unwrap());
|
||||
{
|
||||
let urls = markdown_data.replace(".md)", ".html)");
|
||||
File::create(&preprocessed_path).and_then(|mut f| {
|
||||
f.write_all(urls.as_bytes())
|
||||
})?;
|
||||
}
|
||||
|
||||
// write the prelude to a temporary HTML file for rustdoc inclusion
|
||||
let prelude = tmp.path().join("prelude.html");
|
||||
{
|
||||
let mut buffer = BufWriter::new(File::create(&prelude)?);
|
||||
writeln!(&mut buffer, 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, &mut buffer);
|
||||
writeln!(&mut buffer, "<div id='page-wrapper'>")?;
|
||||
writeln!(&mut buffer, "<div id='page'>")?;
|
||||
}
|
||||
|
||||
// write the postlude to a temporary HTML file for rustdoc inclusion
|
||||
let postlude = tmp.path().join("postlude.html");
|
||||
{
|
||||
let mut buffer = BufWriter::new(File::create(&postlude)?);
|
||||
writeln!(&mut buffer, "<script src='rustbook.js'></script>")?;
|
||||
writeln!(&mut buffer, "</div></div>")?;
|
||||
}
|
||||
|
||||
fs::create_dir_all(&out_path)?;
|
||||
|
||||
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-playground-url=https://play.rust-lang.org/"),
|
||||
format!("--markdown-css={}", item.path_to_root.join("rustbook.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(err(&message));
|
||||
}
|
||||
}
|
||||
|
||||
// create index.html from the root README
|
||||
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 = env::current_dir().unwrap();
|
||||
let src;
|
||||
let tgt;
|
||||
|
||||
if env::args().len() < 3 {
|
||||
src = cwd.clone();
|
||||
} else {
|
||||
src = PathBuf::from(&env::args().nth(2).unwrap());
|
||||
}
|
||||
|
||||
if env::args().len() < 4 {
|
||||
tgt = cwd.join("_book");
|
||||
} else {
|
||||
tgt = PathBuf::from(&env::args().nth(3).unwrap());
|
||||
}
|
||||
|
||||
// `_book` directory may already exist from previous runs. Check and
|
||||
// delete it if it exists.
|
||||
for entry in fs::read_dir(&cwd)? {
|
||||
let path = entry?.path();
|
||||
if path == tgt { fs::remove_dir_all(&tgt)? }
|
||||
}
|
||||
fs::create_dir(&tgt)?;
|
||||
|
||||
// Copy static files
|
||||
let css = include_bytes!("static/rustbook.css");
|
||||
let js = include_bytes!("static/rustbook.js");
|
||||
|
||||
let mut css_file = File::create(tgt.join("rustbook.css"))?;
|
||||
css_file.write_all(css)?;
|
||||
|
||||
let mut js_file = File::create(tgt.join("rustbook.js"))?;
|
||||
js_file.write_all(js)?;
|
||||
|
||||
|
||||
let mut summary = File::open(&src.join("SUMMARY.md"))?;
|
||||
match book::parse_summary(&mut summary, &src) {
|
||||
Ok(book) => {
|
||||
// execute rustdoc on the whole book
|
||||
render(&book, &tgt)
|
||||
}
|
||||
Err(errors) => {
|
||||
let n = errors.len();
|
||||
for err in errors {
|
||||
term.err(&format!("error: {}", err)[..]);
|
||||
}
|
||||
|
||||
Err(err(&format!("{} errors occurred", n)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// 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.
|
||||
|
||||
//! Error handling utilities. WIP.
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
pub type CliError = Box<Error + 'static>;
|
||||
pub type CliResult<T> = Result<T, CliError>;
|
||||
|
||||
pub type CommandError = Box<Error + 'static>;
|
||||
pub type CommandResult<T> = Result<T, CommandError>;
|
||||
|
||||
pub fn err(s: &str) -> CliError {
|
||||
#[derive(Debug)]
|
||||
struct E(String);
|
||||
|
||||
impl Error for E {
|
||||
fn description(&self) -> &str { &self.0 }
|
||||
}
|
||||
impl fmt::Display for E {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(E(s.to_string()))
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
// 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 `help` subcommand. Currently just prints basic usage info.
|
||||
|
||||
use subcommand::Subcommand;
|
||||
use error::CliResult;
|
||||
use error::CommandResult;
|
||||
use term::Term;
|
||||
|
||||
struct Help;
|
||||
|
||||
pub fn parse_cmd(name: &str) -> Option<Box<Subcommand>> {
|
||||
match name {
|
||||
"help" | "--help" | "-h" | "-?" => Some(Box::new(Help)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
impl Subcommand for Help {
|
||||
fn parse_args(&mut self, _: &[String]) -> CliResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn usage(&self) {}
|
||||
fn execute(&mut self, _: &mut Term) -> CommandResult<()> {
|
||||
usage();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn usage() {
|
||||
println!("Usage: rustbook <command> [<args>]");
|
||||
println!("");
|
||||
println!("The <command> must be one of:");
|
||||
println!(" help Print this message.");
|
||||
println!(" build Build the book in subdirectory _book");
|
||||
println!(" serve --NOT YET IMPLEMENTED--");
|
||||
println!(" test --NOT YET IMPLEMENTED--");
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(rustdoc)]
|
||||
|
||||
extern crate rustdoc;
|
||||
extern crate rustc_back;
|
||||
|
||||
use std::env;
|
||||
use std::process;
|
||||
use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
|
||||
use term::Term;
|
||||
|
||||
mod term;
|
||||
mod error;
|
||||
mod book;
|
||||
|
||||
mod subcommand;
|
||||
mod help;
|
||||
mod build;
|
||||
mod serve;
|
||||
mod test;
|
||||
|
||||
static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
|
||||
|
||||
pub fn main() {
|
||||
let mut term = Term::new();
|
||||
let cmd: Vec<_> = env::args().collect();
|
||||
|
||||
if cmd.len() <= 1 {
|
||||
help::usage()
|
||||
} else {
|
||||
match subcommand::parse_name(&cmd[1][..]) {
|
||||
Some(mut subcmd) => {
|
||||
match subcmd.parse_args(&cmd[..cmd.len()-1]) {
|
||||
Ok(_) => {
|
||||
match subcmd.execute(&mut term) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
term.err(&format!("error: {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("{}", err.description());
|
||||
println!("");
|
||||
subcmd.usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
println!("Unrecognized command '{}'.", cmd[1]);
|
||||
println!("");
|
||||
help::usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
process::exit(EXIT_STATUS.load(Ordering::SeqCst) as i32);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// 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 `serve` subcommand. Just a stub for now.
|
||||
|
||||
use subcommand::Subcommand;
|
||||
use error::CliResult;
|
||||
use error::CommandResult;
|
||||
use term::Term;
|
||||
|
||||
struct Serve;
|
||||
|
||||
pub fn parse_cmd(name: &str) -> Option<Box<Subcommand>> {
|
||||
if name == "serve" {
|
||||
Some(Box::new(Serve))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Subcommand for Serve {
|
||||
fn parse_args(&mut self, _: &[String]) -> CliResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn usage(&self) {}
|
||||
fn execute(&mut self, _: &mut Term) -> CommandResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
79
src/tools/rustbook/src/main.rs
Normal file
79
src/tools/rustbook/src/main.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
extern crate mdbook;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use clap::{App, ArgMatches, SubCommand, AppSettings};
|
||||
|
||||
use mdbook::MDBook;
|
||||
|
||||
const NAME: &'static str = "rustbook";
|
||||
|
||||
fn main() {
|
||||
// Create a list of valid arguments and sub-commands
|
||||
let matches = App::new(NAME)
|
||||
.about("Build a book with mdBook")
|
||||
.author("Steve Klabnik <steve@steveklabnik.com>")
|
||||
.version(&*format!("v{}", crate_version!()))
|
||||
.setting(AppSettings::SubcommandRequired)
|
||||
.subcommand(SubCommand::with_name("build")
|
||||
.about("Build the book from the markdown files")
|
||||
.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)'"))
|
||||
.get_matches();
|
||||
|
||||
// Check which subcomamnd the user ran...
|
||||
let res = match matches.subcommand() {
|
||||
("build", Some(sub_matches)) => build(sub_matches),
|
||||
("test", Some(sub_matches)) => test(sub_matches),
|
||||
(_, _) => unreachable!(),
|
||||
};
|
||||
|
||||
if let Err(e) = res {
|
||||
writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
|
||||
::std::process::exit(101);
|
||||
}
|
||||
}
|
||||
|
||||
// Build command implementation
|
||||
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
|
||||
let book_dir = get_book_dir(args);
|
||||
let book = MDBook::new(&book_dir).read_config();
|
||||
|
||||
let mut book = match args.value_of("dest-dir") {
|
||||
Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
|
||||
None => book
|
||||
};
|
||||
|
||||
try!(book.build());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_book_dir(args: &ArgMatches) -> PathBuf {
|
||||
if let Some(dir) = args.value_of("dir") {
|
||||
// Check if path is relative from current dir, or absolute...
|
||||
let p = Path::new(dir);
|
||||
if p.is_relative() {
|
||||
env::current_dir().unwrap().join(dir)
|
||||
} else {
|
||||
p.to_path_buf()
|
||||
}
|
||||
} else {
|
||||
env::current_dir().unwrap()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
/**
|
||||
* Copyright 2013-2015 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.
|
||||
*/
|
||||
|
||||
@import url('../rust.css');
|
||||
|
||||
body {
|
||||
max-width: none;
|
||||
font: 16px/1.6 'Source Serif Pro', Georgia, Times, 'Times New Roman', serif;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Open Sans', 'Fira Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
@media only screen {
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 300px;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
padding: 0 15px;
|
||||
font-size: 14px;
|
||||
background-color: #fafafa;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
#page-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 300px;
|
||||
right: 0;
|
||||
padding: 0 15px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
|
||||
@media only print {
|
||||
#toc, #nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1023px) {
|
||||
#toc {
|
||||
width: 100%;
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
#page-wrapper {
|
||||
top: 40px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.mobile-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#page {
|
||||
margin: 0 auto;
|
||||
max-width: 750px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.chapter {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.section {
|
||||
list-style: none;
|
||||
padding-left: 20px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.section li {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.chapter li a {
|
||||
color: #333;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.chapter li a.active,
|
||||
.chapter li a:hover {
|
||||
color: #008cff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#toggle-nav {
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #666;
|
||||
border-radius: 3px;
|
||||
padding: 3px 3px 0 3px;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.bar {
|
||||
display: block;
|
||||
background-color: #000;
|
||||
border-radius: 2px;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
margin: 2px 0 3px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 11px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f7f7f7;
|
||||
border: 0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
// Copyright 2014-2015 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.
|
||||
|
||||
/*jslint browser: true, es5: true */
|
||||
/*globals $: true, rootPath: true */
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
'use strict';
|
||||
|
||||
document.getElementById('toggle-nav').onclick = function(e) {
|
||||
var toc = document.getElementById('toc');
|
||||
var pagewrapper = document.getElementById('page-wrapper');
|
||||
toggleClass(toc, 'mobile-hidden');
|
||||
toggleClass(pagewrapper, 'mobile-hidden');
|
||||
};
|
||||
|
||||
function toggleClass(el, className) {
|
||||
// from http://youmightnotneedjquery.com/
|
||||
if (el.classList) {
|
||||
el.classList.toggle(className);
|
||||
} else {
|
||||
var classes = el.className.split(' ');
|
||||
var existingIndex = classes.indexOf(className);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
classes.splice(existingIndex, 1);
|
||||
} else {
|
||||
classes.push(className);
|
||||
}
|
||||
|
||||
el.className = classes.join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
// The below code is used to add prev and next navigation links to the
|
||||
// bottom of each of the sections.
|
||||
// It works by extracting the current page based on the url and iterates
|
||||
// over the menu links until it finds the menu item for the current page. We
|
||||
// then create a copy of the preceding and following menu links and add the
|
||||
// correct css class and insert them into the bottom of the page.
|
||||
var toc = document.getElementById('toc').getElementsByTagName('a');
|
||||
var href = document.location.pathname.split('/').pop();
|
||||
|
||||
if (href === 'index.html' || href === '') {
|
||||
href = 'README.html';
|
||||
}
|
||||
|
||||
for (var i = 0; i < toc.length; i++) {
|
||||
if (toc[i].attributes.href.value.split('/').pop() === href) {
|
||||
var nav = document.createElement('p');
|
||||
|
||||
if (i > 0) {
|
||||
var prevNode = toc[i-1].cloneNode(true);
|
||||
prevNode.className = 'left';
|
||||
prevNode.setAttribute('rel', 'prev');
|
||||
nav.appendChild(prevNode);
|
||||
}
|
||||
|
||||
if (i < toc.length - 1) {
|
||||
var nextNode = toc[i+1].cloneNode(true);
|
||||
nextNode.className = 'right';
|
||||
nextNode.setAttribute('rel', 'next');
|
||||
nav.appendChild(nextNode);
|
||||
}
|
||||
|
||||
document.getElementById('page').appendChild(nav);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,44 +0,0 @@
|
|||
// 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.
|
||||
|
||||
//! Common API for all rustbook subcommands.
|
||||
|
||||
use error::CliResult;
|
||||
use error::CommandResult;
|
||||
use term::Term;
|
||||
|
||||
use help;
|
||||
use build;
|
||||
use serve;
|
||||
use test;
|
||||
|
||||
pub trait Subcommand {
|
||||
/// Mutate the subcommand by parsing its arguments.
|
||||
///
|
||||
/// Returns `Err` on a parsing error.
|
||||
fn parse_args(&mut self, args: &[String]) -> CliResult<()>;
|
||||
/// Print the CLI usage information.
|
||||
fn usage(&self);
|
||||
/// Actually execute the subcommand.
|
||||
fn execute(&mut self, term: &mut Term) -> CommandResult<()>;
|
||||
}
|
||||
|
||||
/// Create a Subcommand object based on its name.
|
||||
pub fn parse_name(name: &str) -> Option<Box<Subcommand>> {
|
||||
let cmds: [fn(&str) -> Option<Box<Subcommand>>; 4] = [help::parse_cmd,
|
||||
build::parse_cmd,
|
||||
serve::parse_cmd,
|
||||
test::parse_cmd];
|
||||
for parser in &cmds {
|
||||
let parsed = (*parser)(name);
|
||||
if parsed.is_some() { return parsed }
|
||||
}
|
||||
None
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
// 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.
|
||||
|
||||
//! An abstraction of the terminal. Eventually, provide color and
|
||||
//! verbosity support. For now, just a wrapper around stdout/stderr.
|
||||
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
pub struct Term {
|
||||
err: Box<Write + 'static>
|
||||
}
|
||||
|
||||
impl Term {
|
||||
pub fn new() -> Term {
|
||||
Term {
|
||||
err: Box::new(io::stderr())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn err(&mut self, msg: &str) {
|
||||
// swallow any errors
|
||||
let _ = writeln!(&mut self.err, "{}", msg);
|
||||
::EXIT_STATUS.store(101, Ordering::SeqCst);
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
// 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 `test` subcommand. Just a stub for now.
|
||||
|
||||
use subcommand::Subcommand;
|
||||
use error::{err, CliResult, CommandResult};
|
||||
use term::Term;
|
||||
use book;
|
||||
|
||||
use std::fs::File;
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
|
||||
struct Test;
|
||||
|
||||
pub fn parse_cmd(name: &str) -> Option<Box<Subcommand>> {
|
||||
if name == "test" {
|
||||
Some(Box::new(Test))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Subcommand for Test {
|
||||
fn parse_args(&mut self, _: &[String]) -> CliResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn usage(&self) {}
|
||||
fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
|
||||
let cwd = env::current_dir().unwrap();
|
||||
let src = cwd.clone();
|
||||
|
||||
let mut summary = File::open(&src.join("SUMMARY.md"))?;
|
||||
match book::parse_summary(&mut summary, &src) {
|
||||
Ok(book) => {
|
||||
for (_, item) in book.iter() {
|
||||
let output_result = Command::new("rustdoc")
|
||||
.arg(&item.path)
|
||||
.arg("--test")
|
||||
.output();
|
||||
match output_result {
|
||||
Ok(output) => {
|
||||
if !output.status.success() {
|
||||
term.err(&format!("{}\n{}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)));
|
||||
return Err(err("some tests failed"));
|
||||
}
|
||||
|
||||
}
|
||||
Err(e) => {
|
||||
let message = format!("could not execute `rustdoc`: {}", e);
|
||||
return Err(err(&message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(errors) => {
|
||||
for err in errors {
|
||||
term.err(&err[..]);
|
||||
}
|
||||
return Err(err("there was an error"))
|
||||
}
|
||||
}
|
||||
Ok(()) // lol
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue