From 063e68b0b6db5bd732f1719c5fcfa8837837eb1a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 22:34:13 -0800 Subject: rustbuild: Add `make check` and a check target We'll tack on more steps here later --- src/bootstrap/build/step.rs | 12 ++++++++++++ src/bootstrap/mk/Makefile.in | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index ba0095ce849..fbdcddf3aa0 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -53,11 +53,19 @@ macro_rules! targets { // with braces are unstable so we just pick something that works. (llvm, Llvm { _dummy: () }), (compiler_rt, CompilerRt { _dummy: () }), + + // Steps for various pieces of documentation that we can generate, + // the 'doc' step is just a pseudo target to depend on a bunch of + // others. (doc, Doc { stage: u32 }), (doc_book, DocBook { stage: u32 }), (doc_nomicon, DocNomicon { stage: u32 }), (doc_style, DocStyle { stage: u32 }), (doc_standalone, DocStandalone { stage: u32 }), + + // Steps for running tests. The 'check' target is just a pseudo + // target to depend on a bunch of others. + (check, Check { stage: u32, compiler: Compiler<'a> }), } } } @@ -175,6 +183,7 @@ fn add_steps<'a>(build: &'a Build, "doc-nomicon" => targets.push(host.doc_nomicon(stage)), "doc-book" => targets.push(host.doc_book(stage)), "doc" => targets.push(host.doc(stage)), + "check" => targets.push(host.check(stage, compiler)), _ => panic!("unknown build target: `{}`", step), } } @@ -240,6 +249,9 @@ impl<'a> Step<'a> { vec![self.doc_book(stage), self.doc_nomicon(stage), self.doc_style(stage), self.doc_standalone(stage)] } + Source::Check { stage, compiler: _ } => { + vec![] + } } } } diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index fa3dee2f358..7d793002149 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -36,3 +36,5 @@ book: $(Q)$(BOOTSTRAP) --step doc-book standalone-docs: $(Q)$(BOOTSTRAP) --step doc-standalone +check: + $(Q)$(BOOTSTRAP) --step check -- cgit 1.4.1-3-g733a5 From 6a541937dc314cc9e71062a82119b170dd27e995 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 22:36:21 -0800 Subject: rustbuild: Add crate documentation generation Run `cargo doc` to generate all documentation for the standard library, and also add a target which generates documentation for the compiler as well (but don't enable it by default). --- src/bootstrap/build/doc.rs | 39 ++++++++++++++++++++++++++++++++++++++- src/bootstrap/build/mod.rs | 10 +++++++++- src/bootstrap/build/step.rs | 13 ++++++++++++- src/bootstrap/build/util.rs | 1 - 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/build/doc.rs b/src/bootstrap/build/doc.rs index 937a234bec8..02eda0e7b58 100644 --- a/src/bootstrap/build/doc.rs +++ b/src/bootstrap/build/doc.rs @@ -13,7 +13,7 @@ use std::fs::{self, File}; use std::io::prelude::*; use build::{Build, Compiler}; -use build::util::up_to_date; +use build::util::{up_to_date, cp_r}; pub fn rustbook(build: &Build, stage: u32, host: &str, name: &str, out: &Path) { t!(fs::create_dir_all(out)); @@ -102,3 +102,40 @@ pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) { build.run(&mut cmd); } } + +pub fn std(build: &Build, stage: u32, host: &str, out: &Path) { + println!("Documenting stage{} std ({})", stage, host); + let compiler = Compiler::new(stage, host); + let out_dir = build.stage_out(stage, host, true) + .join(host).join("doc"); + let rustdoc = build.tool(&compiler, "rustdoc"); + if !up_to_date(&rustdoc, &out_dir.join("std/index.html")) { + t!(fs::remove_dir_all(&out_dir)); + } + + let mut cargo = build.cargo(stage, &compiler, true, host, + "doc"); + cargo.arg("--manifest-path") + .arg(build.src.join("src/rustc/std_shim/Cargo.toml")) + .arg("--features").arg(build.std_features()); + build.run(&mut cargo); + cp_r(&out_dir, out) +} + +pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) { + println!("Documenting stage{} compiler ({})", stage, host); + let compiler = Compiler::new(stage, host); + let out_dir = build.stage_out(stage, host, false) + .join(host).join("doc"); + let rustdoc = build.tool(&compiler, "rustdoc"); + if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) { + t!(fs::remove_dir_all(&out_dir)); + } + let mut cargo = build.cargo(stage, &compiler, false, host, + "doc"); + cargo.arg("--manifest-path") + .arg(build.src.join("src/rustc/Cargo.toml")) + .arg("--features").arg(build.rustc_features(stage)); + build.run(&mut cargo); + cp_r(&out_dir, out) +} diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 98d821b8b90..05920a480a9 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -179,7 +179,15 @@ impl Build { DocStandalone { stage } => { doc::standalone(self, stage, target.target, &doc_out); } - Doc { .. } => {} // pseudo-step + DocStd { stage } => { + doc::std(self, stage, target.target, &doc_out); + } + DocRustc { stage } => { + doc::rustc(self, stage, target.target, &doc_out); + } + + Doc { .. } | // pseudo-steps + Check { .. } => {} } } } diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index fbdcddf3aa0..fc8d366faac 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -62,6 +62,8 @@ macro_rules! targets { (doc_nomicon, DocNomicon { stage: u32 }), (doc_style, DocStyle { stage: u32 }), (doc_standalone, DocStandalone { stage: u32 }), + (doc_std, DocStd { stage: u32 }), + (doc_rustc, DocRustc { stage: u32 }), // Steps for running tests. The 'check' target is just a pseudo // target to depend on a bunch of others. @@ -182,6 +184,8 @@ fn add_steps<'a>(build: &'a Build, "doc-standalone" => targets.push(host.doc_standalone(stage)), "doc-nomicon" => targets.push(host.doc_nomicon(stage)), "doc-book" => targets.push(host.doc_book(stage)), + "doc-std" => targets.push(host.doc_std(stage)), + "doc-rustc" => targets.push(host.doc_rustc(stage)), "doc" => targets.push(host.doc(stage)), "check" => targets.push(host.check(stage, compiler)), _ => panic!("unknown build target: `{}`", step), @@ -239,15 +243,22 @@ impl<'a> Step<'a> { vec![self.llvm(()).target(&build.config.build)] } Source::Llvm { _dummy } => Vec::new(), + Source::DocStd { stage } => { + vec![self.libstd(stage, self.compiler(stage))] + } Source::DocBook { stage } | Source::DocNomicon { stage } | Source::DocStyle { stage } | Source::DocStandalone { stage } => { vec![self.rustc(stage)] } + Source::DocRustc { stage } => { + vec![self.doc_std(stage)] + } Source::Doc { stage } => { vec![self.doc_book(stage), self.doc_nomicon(stage), - self.doc_style(stage), self.doc_standalone(stage)] + self.doc_style(stage), self.doc_standalone(stage), + self.doc_std(stage)] } Source::Check { stage, compiler: _ } => { vec![] diff --git a/src/bootstrap/build/util.rs b/src/bootstrap/build/util.rs index 6c700671f11..35d22ee5d26 100644 --- a/src/bootstrap/build/util.rs +++ b/src/bootstrap/build/util.rs @@ -30,7 +30,6 @@ pub fn mtime(path: &Path) -> FileTime { }).unwrap_or(FileTime::zero()) } -#[allow(dead_code)] // this will be used soon pub fn cp_r(src: &Path, dst: &Path) { for f in t!(fs::read_dir(src)) { let f = t!(f); -- cgit 1.4.1-3-g733a5 From 4d3d29dff34b7e041a8947fab13e1a43a714ad12 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 22:50:25 -0800 Subject: rustbuild: Refactor adding steps manually Use a macro so it automatically picks up new steps. --- src/bootstrap/build/step.rs | 47 ++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index fc8d366faac..e47c7311ae4 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -168,28 +168,35 @@ fn add_steps<'a>(build: &'a Build, host: &Step<'a>, target: &Step<'a>, targets: &mut Vec>) { + struct Context<'a> { + stage: u32, + compiler: Compiler<'a>, + _dummy: (), + host: &'a str, + } for step in build.flags.step.iter() { - let compiler = host.target(&build.config.build).compiler(stage); - match &step[..] { - "libstd" => targets.push(target.libstd(stage, compiler)), - "librustc" => targets.push(target.librustc(stage, compiler)), - "libstd-link" => targets.push(target.libstd_link(stage, compiler, - host.target)), - "librustc-link" => targets.push(target.librustc_link(stage, compiler, - host.target)), - "rustc" => targets.push(host.rustc(stage)), - "llvm" => targets.push(target.llvm(())), - "compiler-rt" => targets.push(target.compiler_rt(())), - "doc-style" => targets.push(host.doc_style(stage)), - "doc-standalone" => targets.push(host.doc_standalone(stage)), - "doc-nomicon" => targets.push(host.doc_nomicon(stage)), - "doc-book" => targets.push(host.doc_book(stage)), - "doc-std" => targets.push(host.doc_std(stage)), - "doc-rustc" => targets.push(host.doc_rustc(stage)), - "doc" => targets.push(host.doc(stage)), - "check" => targets.push(host.check(stage, compiler)), - _ => panic!("unknown build target: `{}`", step), + + // The macro below insists on hygienic access to all local variables, so + // we shove them all in a struct and subvert hygiene by accessing struct + // fields instead, + let cx = Context { + stage: stage, + compiler: host.target(&build.config.build).compiler(stage), + _dummy: (), + host: host.target, + }; + macro_rules! add_step { + ($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => ({$( + let name = stringify!($short).replace("_", "-"); + if &step[..] == &name[..] { + targets.push(target.$short($(cx.$arg),*)); + continue + } + drop(name); + )*}) } + + targets!(add_step); } } -- cgit 1.4.1-3-g733a5 From ee6df13f0c25ce567b12459d1f34216334832920 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 22:32:37 -0800 Subject: rustbuild: Move rustbook to a `src/tools` directory We've actually got quite a few tools that are compiled as part of our build, let's start housing them all in a `tools` directory. --- mk/crates.mk | 2 +- src/bootstrap/build/compile.rs | 25 ++++ src/bootstrap/build/mod.rs | 20 ++- src/bootstrap/build/step.rs | 9 +- src/rustbook/Cargo.toml | 13 -- src/rustbook/book.rs | 171 ------------------------- src/rustbook/build.rs | 225 --------------------------------- src/rustbook/error.rs | 36 ------ src/rustbook/help.rs | 46 ------- src/rustbook/main.rs | 72 ----------- src/rustbook/serve.rs | 36 ------ src/rustbook/static/rustbook.css | 157 ----------------------- src/rustbook/static/rustbook.js | 78 ------------ src/rustbook/subcommand.rs | 44 ------- src/rustbook/term.rs | 34 ----- src/rustbook/test.rs | 75 ----------- src/rustc/Cargo.lock | 9 -- src/rustc/Cargo.toml | 5 - src/rustc/rustbook.rs | 14 -- src/tools/rustbook/Cargo.lock | 4 + src/tools/rustbook/Cargo.toml | 8 ++ src/tools/rustbook/book.rs | 171 +++++++++++++++++++++++++ src/tools/rustbook/build.rs | 225 +++++++++++++++++++++++++++++++++ src/tools/rustbook/error.rs | 36 ++++++ src/tools/rustbook/help.rs | 46 +++++++ src/tools/rustbook/main.rs | 72 +++++++++++ src/tools/rustbook/serve.rs | 36 ++++++ src/tools/rustbook/static/rustbook.css | 157 +++++++++++++++++++++++ src/tools/rustbook/static/rustbook.js | 78 ++++++++++++ src/tools/rustbook/subcommand.rs | 44 +++++++ src/tools/rustbook/term.rs | 34 +++++ src/tools/rustbook/test.rs | 75 +++++++++++ 32 files changed, 1028 insertions(+), 1029 deletions(-) delete mode 100644 src/rustbook/Cargo.toml delete mode 100644 src/rustbook/book.rs delete mode 100644 src/rustbook/build.rs delete mode 100644 src/rustbook/error.rs delete mode 100644 src/rustbook/help.rs delete mode 100644 src/rustbook/main.rs delete mode 100644 src/rustbook/serve.rs delete mode 100644 src/rustbook/static/rustbook.css delete mode 100644 src/rustbook/static/rustbook.js delete mode 100644 src/rustbook/subcommand.rs delete mode 100644 src/rustbook/term.rs delete mode 100644 src/rustbook/test.rs delete mode 100644 src/rustc/rustbook.rs create mode 100644 src/tools/rustbook/Cargo.lock create mode 100644 src/tools/rustbook/Cargo.toml create mode 100644 src/tools/rustbook/book.rs create mode 100644 src/tools/rustbook/build.rs create mode 100644 src/tools/rustbook/error.rs create mode 100644 src/tools/rustbook/help.rs create mode 100644 src/tools/rustbook/main.rs create mode 100644 src/tools/rustbook/serve.rs create mode 100644 src/tools/rustbook/static/rustbook.css create mode 100644 src/tools/rustbook/static/rustbook.js create mode 100644 src/tools/rustbook/subcommand.rs create mode 100644 src/tools/rustbook/term.rs create mode 100644 src/tools/rustbook/test.rs diff --git a/mk/crates.mk b/mk/crates.mk index b7bb7c1083d..f7fd74e8c9f 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -125,7 +125,7 @@ TOOL_DEPS_error_index_generator := rustdoc syntax serialize TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs TOOL_SOURCE_rustc := $(S)src/driver/driver.rs -TOOL_SOURCE_rustbook := $(S)src/rustbook/main.rs +TOOL_SOURCE_rustbook := $(S)src/tools/rustbook/main.rs TOOL_SOURCE_error_index_generator := $(S)src/error_index_generator/main.rs ONLY_RLIB_core := 1 diff --git a/src/bootstrap/build/compile.rs b/src/bootstrap/build/compile.rs index fb0a840bfa2..a027ac0fd60 100644 --- a/src/bootstrap/build/compile.rs +++ b/src/bootstrap/build/compile.rs @@ -298,3 +298,28 @@ fn add_to_sysroot(out_dir: &Path, sysroot_dst: &Path) { sysroot_dst.join(path.file_name().unwrap()))); } } + +/// Build a tool in `src/tools` +/// +/// This will build the specified tool with the specified `host` compiler in +/// `stage` into the normal cargo output directory. +pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) { + println!("Building stage{} tool {} ({})", stage, tool, host); + + let compiler = Compiler::new(stage, host); + + // FIXME: need to clear out previous tool and ideally deps, may require + // isolating output directories or require a pseudo shim step to + // clear out all the info. + // + // Maybe when libstd is compiled it should clear out the rustc of the + // corresponding stage? + // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); + // build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target)); + + let mut cargo = build.cargo(stage, &compiler, Mode::Tool, None, "build"); + cargo.arg("--manifest-path") + .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool))); + build.run(&mut cargo); +} + diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 05920a480a9..8449c237816 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -165,6 +165,9 @@ impl Build { Rustc { stage } => { compile::assemble_rustc(self, stage, target.target); } + ToolRustbook { stage } => { + compile::tool(self, stage, target.target, "rustbook"); + } DocBook { stage } => { doc::rustbook(self, stage, target.target, "book", &doc_out); } @@ -303,15 +306,9 @@ impl Build { /// Get the specified tool next to the specified compiler fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf { - if compiler.is_snapshot(self) { - assert!(tool == "rustdoc", "no tools other than rustdoc in stage0"); - let mut rustdoc = self.rustc.clone(); - rustdoc.pop(); - rustdoc.push(exe("rustdoc", &self.config.build)); - return rustdoc - } - let (stage, host) = (compiler.stage, compiler.host); - self.cargo_out(stage - 1, host, false, host).join(exe(tool, host)) + self.stage_out(compiler.stage, compiler.host, false) + .join(self.cargo_dir()) + .join(exe(tool, compiler.host)) } /// Get a `Command` which is ready to run `tool` in `stage` built for @@ -322,8 +319,8 @@ impl Build { let host = compiler.host; let stage = compiler.stage; let paths = vec![ - self.cargo_out(stage - 1, host, true, host).join("deps"), - self.cargo_out(stage - 1, host, false, host).join("deps"), + self.cargo_out(stage, host, true, host).join("deps"), + self.cargo_out(stage, host, false, host).join("deps"), ]; add_lib_path(paths, &mut cmd); return cmd @@ -354,7 +351,6 @@ impl Build { } if stage > 0 { features.push_str(" rustdoc"); - features.push_str(" rustbook"); } return features } diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index e47c7311ae4..23c678df9ac 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -45,6 +45,9 @@ macro_rules! targets { host: &'a str }), + // Various tools that we can build as part of the build. + (tool_rustbook, ToolRustbook { stage: u32 }), + // Steps for long-running native builds. Ideally these wouldn't // actually exist and would be part of build scripts, but for now // these are here. @@ -255,7 +258,9 @@ impl<'a> Step<'a> { } Source::DocBook { stage } | Source::DocNomicon { stage } | - Source::DocStyle { stage } | + Source::DocStyle { stage } => { + vec![self.tool_rustbook(stage)] + } Source::DocStandalone { stage } => { vec![self.rustc(stage)] } @@ -269,6 +274,8 @@ impl<'a> Step<'a> { } Source::Check { stage, compiler: _ } => { vec![] + Source::ToolRustbook { stage } => { + vec![self.librustc(stage, self.compiler(stage))] } } } diff --git a/src/rustbook/Cargo.toml b/src/rustbook/Cargo.toml deleted file mode 100644 index c684c474efa..00000000000 --- a/src/rustbook/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustbook" -version = "0.0.0" - -[lib] -name = "rustbook" -path = "main.rs" -crate-type = ["dylib"] - -[dependencies] -rustc_back = { path = "../librustc_back" } -rustdoc = { path = "../librustdoc" } diff --git a/src/rustbook/book.rs b/src/rustbook/book.rs deleted file mode 100644 index 36a37dba1fa..00000000000 --- a/src/rustbook/book.rs +++ /dev/null @@ -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 or the MIT license -// , 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, -} - -pub struct Book { - pub chapters: Vec, -} - -/// 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> { - fn collapse(stack: &mut Vec, - top_items: &mut Vec, - 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::()); - 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::() / 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) - } -} diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs deleted file mode 100644 index 4b6d67d2d26..00000000000 --- a/src/rustbook/build.rs +++ /dev/null @@ -1,225 +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 or the MIT license -// , 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> { - 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() { - try!(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 { - "" - }; - - try!(writeln!(out, "
  • {} {}", - class_string, - current_page.path_to_root.join(&item.path).with_extension("html").display(), - section, - item.title)); - if !item.children.is_empty() { - try!(writeln!(out, "
      ")); - let _ = walk_items(&item.children[..], section, current_page, out); - try!(writeln!(out, "
    ")); - } - try!(writeln!(out, "
  • ")); - - Ok(()) - } - - try!(writeln!(out, "
    ")); - try!(writeln!(out, "
      ")); - try!(walk_items(&book.chapters[..], "", ¤t_page, out)); - try!(writeln!(out, "
    ")); - try!(writeln!(out, "
    ")); - - Ok(()) -} - -fn render(book: &Book, tgt: &Path) -> CliResult<()> { - let tmp = try!(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(); - try!(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)"); - try!(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(try!(File::create(&prelude))); - try!(writeln!(&mut buffer, r#" - "#)); - let _ = write_toc(book, &item, &mut buffer); - try!(writeln!(&mut buffer, "
    ")); - try!(writeln!(&mut buffer, "
    ")); - } - - // write the postlude to a temporary HTML file for rustdoc inclusion - let postlude = tmp.path().join("postlude.html"); - { - let mut buffer = BufWriter::new(try!(File::create(&postlude))); - try!(writeln!(&mut buffer, "")); - try!(writeln!(&mut buffer, "")); - try!(writeln!(&mut buffer, "
    ")); - } - - try!(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 - try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html"))); - - // Copy js for playpen - let mut playpen = try!(File::create(tgt.join("playpen.js"))); - let js = include_bytes!("../librustdoc/html/static/playpen.js"); - try!(playpen.write_all(js)); - 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 try!(fs::read_dir(&cwd)) { - let path = try!(entry).path(); - if path == tgt { try!(fs::remove_dir_all(&tgt)) } - } - try!(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 = try!(File::create(tgt.join("rustbook.css"))); - try!(css_file.write_all(css)); - - let mut js_file = try!(File::create(tgt.join("rustbook.js"))); - try!(js_file.write_all(js)); - - - let mut summary = try!(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))) - } - } - } -} diff --git a/src/rustbook/error.rs b/src/rustbook/error.rs deleted file mode 100644 index e896dee2791..00000000000 --- a/src/rustbook/error.rs +++ /dev/null @@ -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 or the MIT license -// , 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; -pub type CliResult = Result; - -pub type CommandError = Box; -pub type CommandResult = Result; - -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())) -} diff --git a/src/rustbook/help.rs b/src/rustbook/help.rs deleted file mode 100644 index c90c2b93609..00000000000 --- a/src/rustbook/help.rs +++ /dev/null @@ -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 or the MIT license -// , 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> { - 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 []"); - println!(""); - println!("The 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--"); -} diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs deleted file mode 100644 index bd4fc899293..00000000000 --- a/src/rustbook/main.rs +++ /dev/null @@ -1,72 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![deny(warnings)] - -#![feature(iter_arith)] -#![feature(rustc_private)] -#![feature(rustdoc)] - -extern crate rustdoc; -extern crate rustc_back; - -use std::env; -use std::error::Error; -use std::process; -use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering}; -use subcommand::Subcommand; -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); -} diff --git a/src/rustbook/serve.rs b/src/rustbook/serve.rs deleted file mode 100644 index 2fa7b7eed7b..00000000000 --- a/src/rustbook/serve.rs +++ /dev/null @@ -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 or the MIT license -// , 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> { - 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(()) - } -} diff --git a/src/rustbook/static/rustbook.css b/src/rustbook/static/rustbook.css deleted file mode 100644 index ba0151fa2ed..00000000000 --- a/src/rustbook/static/rustbook.css +++ /dev/null @@ -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 or the MIT license - * , 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; -} diff --git a/src/rustbook/static/rustbook.js b/src/rustbook/static/rustbook.js deleted file mode 100644 index d8ab15260ed..00000000000 --- a/src/rustbook/static/rustbook.js +++ /dev/null @@ -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 or the MIT license -// , 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; - } - } -}); diff --git a/src/rustbook/subcommand.rs b/src/rustbook/subcommand.rs deleted file mode 100644 index a66c2b4f302..00000000000 --- a/src/rustbook/subcommand.rs +++ /dev/null @@ -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 or the MIT license -// , 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> { - let cmds: [fn(&str) -> Option>; 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 -} diff --git a/src/rustbook/term.rs b/src/rustbook/term.rs deleted file mode 100644 index cdd25e67c8f..00000000000 --- a/src/rustbook/term.rs +++ /dev/null @@ -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 or the MIT license -// , 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 -} - -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); - } -} diff --git a/src/rustbook/test.rs b/src/rustbook/test.rs deleted file mode 100644 index 72df0768e7b..00000000000 --- a/src/rustbook/test.rs +++ /dev/null @@ -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 or the MIT license -// , 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> { - 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 = try!(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 - } -} diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index e4432720ab4..a2718351640 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -2,7 +2,6 @@ name = "rustc-main" version = "0.0.0" dependencies = [ - "rustbook 0.0.0", "rustc_back 0.0.0", "rustc_driver 0.0.0", "rustdoc 0.0.0", @@ -66,14 +65,6 @@ dependencies = [ "serialize 0.0.0", ] -[[package]] -name = "rustbook" -version = "0.0.0" -dependencies = [ - "rustc_back 0.0.0", - "rustdoc 0.0.0", -] - [[package]] name = "rustc" version = "0.0.0" diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml index 9fcefd9d3a4..f1abf35cbc0 100644 --- a/src/rustc/Cargo.toml +++ b/src/rustc/Cargo.toml @@ -11,10 +11,6 @@ path = "rustc.rs" name = "rustdoc" path = "rustdoc.rs" -[[bin]] -name = "rustbook" -path = "rustbook.rs" - [profile.release] opt-level = 2 @@ -27,7 +23,6 @@ debug-assertions = false # All optional dependencies so the features passed to this Cargo.toml select # what should actually be built. [dependencies] -rustbook = { path = "../rustbook", optional = true } rustc_back = { path = "../librustc_back" } rustc_driver = { path = "../librustc_driver" } rustdoc = { path = "../librustdoc", optional = true } diff --git a/src/rustc/rustbook.rs b/src/rustc/rustbook.rs deleted file mode 100644 index 6f78f78bc55..00000000000 --- a/src/rustc/rustbook.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern crate rustbook; - -fn main() { rustbook::main() } - diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock new file mode 100644 index 00000000000..e541ce4b2b8 --- /dev/null +++ b/src/tools/rustbook/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "rustbook" +version = "0.0.0" + diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml new file mode 100644 index 00000000000..956392ca540 --- /dev/null +++ b/src/tools/rustbook/Cargo.toml @@ -0,0 +1,8 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustbook" +version = "0.0.0" + +[[bin]] +name = "rustbook" +path = "main.rs" diff --git a/src/tools/rustbook/book.rs b/src/tools/rustbook/book.rs new file mode 100644 index 00000000000..36a37dba1fa --- /dev/null +++ b/src/tools/rustbook/book.rs @@ -0,0 +1,171 @@ +// 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 or the MIT license +// , 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, +} + +pub struct Book { + pub chapters: Vec, +} + +/// 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> { + fn collapse(stack: &mut Vec, + top_items: &mut Vec, + 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::()); + 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::() / 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) + } +} diff --git a/src/tools/rustbook/build.rs b/src/tools/rustbook/build.rs new file mode 100644 index 00000000000..70ed98519f9 --- /dev/null +++ b/src/tools/rustbook/build.rs @@ -0,0 +1,225 @@ +// 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 or the MIT license +// , 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> { + 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() { + try!(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 { + "" + }; + + try!(writeln!(out, "
  • {} {}", + class_string, + current_page.path_to_root.join(&item.path).with_extension("html").display(), + section, + item.title)); + if !item.children.is_empty() { + try!(writeln!(out, "
      ")); + let _ = walk_items(&item.children[..], section, current_page, out); + try!(writeln!(out, "
    ")); + } + try!(writeln!(out, "
  • ")); + + Ok(()) + } + + try!(writeln!(out, "
    ")); + try!(writeln!(out, "
      ")); + try!(walk_items(&book.chapters[..], "", ¤t_page, out)); + try!(writeln!(out, "
    ")); + try!(writeln!(out, "
    ")); + + Ok(()) +} + +fn render(book: &Book, tgt: &Path) -> CliResult<()> { + let tmp = try!(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(); + try!(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)"); + try!(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(try!(File::create(&prelude))); + try!(writeln!(&mut buffer, r#" + "#)); + let _ = write_toc(book, &item, &mut buffer); + try!(writeln!(&mut buffer, "
    ")); + try!(writeln!(&mut buffer, "
    ")); + } + + // write the postlude to a temporary HTML file for rustdoc inclusion + let postlude = tmp.path().join("postlude.html"); + { + let mut buffer = BufWriter::new(try!(File::create(&postlude))); + try!(writeln!(&mut buffer, "")); + try!(writeln!(&mut buffer, "")); + try!(writeln!(&mut buffer, "
    ")); + } + + try!(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 + try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html"))); + + // Copy js for playpen + let mut playpen = try!(File::create(tgt.join("playpen.js"))); + let js = include_bytes!("../../librustdoc/html/static/playpen.js"); + try!(playpen.write_all(js)); + 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 try!(fs::read_dir(&cwd)) { + let path = try!(entry).path(); + if path == tgt { try!(fs::remove_dir_all(&tgt)) } + } + try!(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 = try!(File::create(tgt.join("rustbook.css"))); + try!(css_file.write_all(css)); + + let mut js_file = try!(File::create(tgt.join("rustbook.js"))); + try!(js_file.write_all(js)); + + + let mut summary = try!(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))) + } + } + } +} diff --git a/src/tools/rustbook/error.rs b/src/tools/rustbook/error.rs new file mode 100644 index 00000000000..e896dee2791 --- /dev/null +++ b/src/tools/rustbook/error.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , 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; +pub type CliResult = Result; + +pub type CommandError = Box; +pub type CommandResult = Result; + +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())) +} diff --git a/src/tools/rustbook/help.rs b/src/tools/rustbook/help.rs new file mode 100644 index 00000000000..c90c2b93609 --- /dev/null +++ b/src/tools/rustbook/help.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , 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> { + 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 []"); + println!(""); + println!("The 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--"); +} diff --git a/src/tools/rustbook/main.rs b/src/tools/rustbook/main.rs new file mode 100644 index 00000000000..bd4fc899293 --- /dev/null +++ b/src/tools/rustbook/main.rs @@ -0,0 +1,72 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(warnings)] + +#![feature(iter_arith)] +#![feature(rustc_private)] +#![feature(rustdoc)] + +extern crate rustdoc; +extern crate rustc_back; + +use std::env; +use std::error::Error; +use std::process; +use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering}; +use subcommand::Subcommand; +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); +} diff --git a/src/tools/rustbook/serve.rs b/src/tools/rustbook/serve.rs new file mode 100644 index 00000000000..2fa7b7eed7b --- /dev/null +++ b/src/tools/rustbook/serve.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , 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> { + 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(()) + } +} diff --git a/src/tools/rustbook/static/rustbook.css b/src/tools/rustbook/static/rustbook.css new file mode 100644 index 00000000000..ba0151fa2ed --- /dev/null +++ b/src/tools/rustbook/static/rustbook.css @@ -0,0 +1,157 @@ +/** + * 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 or the MIT license + * , 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; +} diff --git a/src/tools/rustbook/static/rustbook.js b/src/tools/rustbook/static/rustbook.js new file mode 100644 index 00000000000..d8ab15260ed --- /dev/null +++ b/src/tools/rustbook/static/rustbook.js @@ -0,0 +1,78 @@ +// 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 or the MIT license +// , 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; + } + } +}); diff --git a/src/tools/rustbook/subcommand.rs b/src/tools/rustbook/subcommand.rs new file mode 100644 index 00000000000..a66c2b4f302 --- /dev/null +++ b/src/tools/rustbook/subcommand.rs @@ -0,0 +1,44 @@ +// 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 or the MIT license +// , 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> { + let cmds: [fn(&str) -> Option>; 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 +} diff --git a/src/tools/rustbook/term.rs b/src/tools/rustbook/term.rs new file mode 100644 index 00000000000..cdd25e67c8f --- /dev/null +++ b/src/tools/rustbook/term.rs @@ -0,0 +1,34 @@ +// 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 or the MIT license +// , 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 +} + +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); + } +} diff --git a/src/tools/rustbook/test.rs b/src/tools/rustbook/test.rs new file mode 100644 index 00000000000..72df0768e7b --- /dev/null +++ b/src/tools/rustbook/test.rs @@ -0,0 +1,75 @@ +// 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 or the MIT license +// , 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> { + 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 = try!(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 + } +} -- cgit 1.4.1-3-g733a5 From 0788cd23ea6e3f1b05240d591870899b9d38f5f4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 22:58:59 -0800 Subject: rustbuild: Use an enum to indicate destination Instead of using a `is_std: bool`, instead use a more well-typed and self-documenting enum to indicate the mode in which Cargo is being invoked. --- src/bootstrap/build/compile.rs | 21 ++++++------ src/bootstrap/build/doc.rs | 10 +++--- src/bootstrap/build/mod.rs | 73 +++++++++++++++++++++++++----------------- 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/bootstrap/build/compile.rs b/src/bootstrap/build/compile.rs index a027ac0fd60..db8c3e50907 100644 --- a/src/bootstrap/build/compile.rs +++ b/src/bootstrap/build/compile.rs @@ -16,7 +16,7 @@ use std::process::Command; use build_helper::output; use build::util::{exe, staticlib, libdir, mtime, is_dylib}; -use build::{Build, Compiler}; +use build::{Build, Compiler, Mode}; /// Build the standard library. /// @@ -39,9 +39,10 @@ pub fn std<'a>(build: &'a Build, stage: u32, target: &str, build_startup_objects(build, target, &libdir); - let out_dir = build.cargo_out(stage, &host, true, target); + let out_dir = build.cargo_out(stage, &host, Mode::Libstd, target); build.clear_if_dirty(&out_dir, &build.compiler_path(compiler)); - let mut cargo = build.cargo(stage, compiler, true, target, "build"); + let mut cargo = build.cargo(stage, compiler, Mode::Libstd, Some(target), + "build"); cargo.arg("--features").arg(build.std_features()) .arg("--manifest-path") .arg(build.src.join("src/rustc/std_shim/Cargo.toml")); @@ -71,7 +72,7 @@ pub fn std_link(build: &Build, compiler: &Compiler, host: &str) { let libdir = build.sysroot_libdir(stage, host, target); - let out_dir = build.cargo_out(stage, compiler.host, true, target); + let out_dir = build.cargo_out(stage, compiler.host, Mode::Libstd, target); // If we're linking one compiler host's output into another, then we weren't // called from the `std` method above. In that case we clean out what's @@ -135,10 +136,11 @@ pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str, println!("Building stage{} compiler artifacts ({} -> {})", stage, host, target); - let out_dir = build.cargo_out(stage, &host, false, target); + let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target)); - let mut cargo = build.cargo(stage, compiler, false, target, "build"); + let mut cargo = build.cargo(stage, compiler, Mode::Librustc, Some(target), + "build"); cargo.arg("--features").arg(build.rustc_features(stage)) .arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")); @@ -200,14 +202,14 @@ pub fn rustc_link(build: &Build, compiler: &Compiler, host: &str) { let libdir = build.sysroot_libdir(stage, host, target); - let out_dir = build.cargo_out(stage, compiler.host, false, target); + let out_dir = build.cargo_out(stage, compiler.host, Mode::Librustc, target); add_to_sysroot(&out_dir, &libdir); } /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. fn libstd_shim(build: &Build, stage: u32, host: &str, target: &str) -> PathBuf { - build.cargo_out(stage, host, true, target).join("libstd_shim.rlib") + build.cargo_out(stage, host, Mode::Libstd, target).join("libstd_shim.rlib") } fn compiler_file(compiler: &Path, file: &str) -> String { @@ -239,7 +241,8 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) { } } - let out_dir = build.cargo_out(stage - 1, &build.config.build, false, host); + let out_dir = build.cargo_out(stage - 1, &build.config.build, + Mode::Librustc, host); // Link the compiler binary itself into place let rustc = out_dir.join(exe("rustc", host)); diff --git a/src/bootstrap/build/doc.rs b/src/bootstrap/build/doc.rs index 02eda0e7b58..5107b4e1353 100644 --- a/src/bootstrap/build/doc.rs +++ b/src/bootstrap/build/doc.rs @@ -12,7 +12,7 @@ use std::path::Path; use std::fs::{self, File}; use std::io::prelude::*; -use build::{Build, Compiler}; +use build::{Build, Compiler, Mode}; use build::util::{up_to_date, cp_r}; pub fn rustbook(build: &Build, stage: u32, host: &str, name: &str, out: &Path) { @@ -106,14 +106,14 @@ pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) { pub fn std(build: &Build, stage: u32, host: &str, out: &Path) { println!("Documenting stage{} std ({})", stage, host); let compiler = Compiler::new(stage, host); - let out_dir = build.stage_out(stage, host, true) + let out_dir = build.stage_out(stage, host, Mode::Libstd) .join(host).join("doc"); let rustdoc = build.tool(&compiler, "rustdoc"); if !up_to_date(&rustdoc, &out_dir.join("std/index.html")) { t!(fs::remove_dir_all(&out_dir)); } - let mut cargo = build.cargo(stage, &compiler, true, host, + let mut cargo = build.cargo(stage, &compiler, Mode::Libstd, Some(host), "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/std_shim/Cargo.toml")) @@ -125,13 +125,13 @@ pub fn std(build: &Build, stage: u32, host: &str, out: &Path) { pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) { println!("Documenting stage{} compiler ({})", stage, host); let compiler = Compiler::new(stage, host); - let out_dir = build.stage_out(stage, host, false) + let out_dir = build.stage_out(stage, host, Mode::Librustc) .join(host).join("doc"); let rustdoc = build.tool(&compiler, "rustdoc"); if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) { t!(fs::remove_dir_all(&out_dir)); } - let mut cargo = build.cargo(stage, &compiler, false, host, + let mut cargo = build.cargo(stage, &compiler, Mode::Librustc, Some(host), "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")) diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 8449c237816..3acd34b4e94 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -83,6 +83,12 @@ pub struct Build { compiler_rt_built: RefCell>, } +pub enum Mode { + Libstd, + Librustc, + Tool, +} + impl Build { pub fn new(flags: Flags, config: Config) -> Build { let cwd = t!(env::current_dir()); @@ -241,14 +247,17 @@ impl Build { /// Cargo for the specified stage, whether or not the standard library is /// being built, and using the specified compiler targeting `target`. // FIXME: aren't stage/compiler duplicated? - fn cargo(&self, stage: u32, compiler: &Compiler, is_std: bool, - target: &str, cmd: &str) -> Command { + fn cargo(&self, + stage: u32, + compiler: &Compiler, + mode: Mode, + target: Option<&str>, + cmd: &str) -> Command { let mut cargo = Command::new(&self.cargo); let host = compiler.host; - let out_dir = self.stage_out(stage, host, is_std); + let out_dir = self.stage_out(stage, host, mode); cargo.env("CARGO_TARGET_DIR", out_dir) .arg(cmd) - .arg("--target").arg(target) .arg("-j").arg(self.jobs().to_string()); // Customize the compiler we're running. Specify the compiler to cargo @@ -265,24 +274,28 @@ impl Build { .env("RUSTC_SNAPSHOT", &self.rustc) .env("RUSTC_SYSROOT", self.sysroot(stage, host)) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()) - .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")) .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) .env("RUSTDOC", self.tool(compiler, "rustdoc")); - // Specify some variuos options for build scripts used throughout the - // build. - // - // FIXME: the guard against msvc shouldn't need to be here - if !target.contains("msvc") { - cargo.env(format!("CC_{}", target), self.cc(target)) - .env(format!("AR_{}", target), self.ar(target)) - .env(format!("CFLAGS_{}", target), self.cflags(target)); - } + if let Some(target) = target { + cargo.env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + cargo.arg("--target").arg(target); + + // Specify some various options for build scripts used throughout + // the build. + // + // FIXME: the guard against msvc shouldn't need to be here + if !target.contains("msvc") { + cargo.env(format!("CC_{}", target), self.cc(target)) + .env(format!("AR_{}", target), self.ar(target)) + .env(format!("CFLAGS_{}", target), self.cflags(target)); + } - // Environment variables *required* needed throughout the build - // - // FIXME: should update code to not require this env vars - cargo.env("CFG_COMPILER_HOST_TRIPLE", target); + // Environment variables *required* needed throughout the build + // + // FIXME: should update code to not require this env vars + cargo.env("CFG_COMPILER_HOST_TRIPLE", target); + } if self.config.verbose || self.flags.verbose { cargo.arg("-v"); @@ -306,7 +319,7 @@ impl Build { /// Get the specified tool next to the specified compiler fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf { - self.stage_out(compiler.stage, compiler.host, false) + self.stage_out(compiler.stage, compiler.host, Mode::Tool) .join(self.cargo_dir()) .join(exe(tool, compiler.host)) } @@ -319,8 +332,8 @@ impl Build { let host = compiler.host; let stage = compiler.stage; let paths = vec![ - self.cargo_out(stage, host, true, host).join("deps"), - self.cargo_out(stage, host, false, host).join("deps"), + self.cargo_out(stage, host, Mode::Libstd, host).join("deps"), + self.cargo_out(stage, host, Mode::Librustc, host).join("deps"), ]; add_lib_path(paths, &mut cmd); return cmd @@ -363,7 +376,7 @@ impl Build { fn sysroot(&self, stage: u32, host: &str) -> PathBuf { if stage == 0 { - self.stage_out(stage, host, false) + self.stage_out(stage, host, Mode::Librustc) } else { self.out.join(host).join(format!("stage{}", stage)) } @@ -377,19 +390,21 @@ impl Build { /// Returns the root directory for all output generated in a particular /// stage when running with a particular host compiler. /// - /// The `is_std` flag indicates whether the root directory is for the - /// bootstrap of the standard library or for the compiler. - fn stage_out(&self, stage: u32, host: &str, is_std: bool) -> PathBuf { - self.out.join(host) - .join(format!("stage{}{}", stage, if is_std {"-std"} else {"-rustc"})) + /// The mode indicates what the root directory is for. + fn stage_out(&self, stage: u32, host: &str, mode: Mode) -> PathBuf { + let suffix = match mode { + Mode::Libstd => "-std", + _ => "-rustc", + }; + self.out.join(host).join(format!("stage{}{}", stage, suffix)) } /// Returns the root output directory for all Cargo output in a given stage, /// running a particular comipler, wehther or not we're building the /// standard library, and targeting the specified architecture. - fn cargo_out(&self, stage: u32, host: &str, is_std: bool, + fn cargo_out(&self, stage: u32, host: &str, mode: Mode, target: &str) -> PathBuf { - self.stage_out(stage, host, is_std).join(target).join(self.cargo_dir()) + self.stage_out(stage, host, mode).join(target).join(self.cargo_dir()) } /// Root output directory for LLVM compiled for `target` -- cgit 1.4.1-3-g733a5 From f7b7535fd7cc4df3c137c5ce05bcd9817e8e006c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 23:11:05 -0800 Subject: rustbuild: Fixup calling rustdoc in various stages The stage0 rustdoc comes from the snapshot, and we need a shim like with `rustc` to pass `--cfg` for now. --- src/bootstrap/Cargo.toml | 4 ++++ src/bootstrap/build/compile.rs | 1 - src/bootstrap/build/doc.rs | 16 ++++++++-------- src/bootstrap/build/mod.rs | 18 ++++++++++++++++-- src/bootstrap/rustc.rs | 17 +++++++++++++++++ src/bootstrap/rustdoc.rs | 31 +++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 src/bootstrap/rustdoc.rs diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 8321f93c90f..0d334219b4f 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -15,6 +15,10 @@ path = "main.rs" name = "rustc" path = "rustc.rs" +[[bin]] +name = "rustdoc" +path = "rustdoc.rs" + [dependencies] build_helper = { path = "../build_helper" } cmake = "0.1.10" diff --git a/src/bootstrap/build/compile.rs b/src/bootstrap/build/compile.rs index db8c3e50907..c4d6e66b878 100644 --- a/src/bootstrap/build/compile.rs +++ b/src/bootstrap/build/compile.rs @@ -325,4 +325,3 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) { .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool))); build.run(&mut cargo); } - diff --git a/src/bootstrap/build/doc.rs b/src/bootstrap/build/doc.rs index 5107b4e1353..917860962c9 100644 --- a/src/bootstrap/build/doc.rs +++ b/src/bootstrap/build/doc.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::path::Path; use std::fs::{self, File}; use std::io::prelude::*; +use std::path::Path; +use std::process::Command; use build::{Build, Compiler, Mode}; use build::util::{up_to_date, cp_r}; @@ -69,7 +70,7 @@ pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) { } let html = out.join(filename).with_extension("html"); - let rustdoc = build.tool(&compiler, "rustdoc"); + let rustdoc = build.rustdoc(&compiler); if up_to_date(&path, &html) && up_to_date(&footer, &html) && up_to_date(&favicon, &html) && @@ -79,7 +80,7 @@ pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) { continue } - let mut cmd = build.tool_cmd(&compiler, "rustdoc"); + let mut cmd = Command::new(&rustdoc); cmd.arg("--html-after-content").arg(&footer) .arg("--html-before-content").arg(&version_info) .arg("--html-in-header").arg(&favicon) @@ -108,10 +109,9 @@ pub fn std(build: &Build, stage: u32, host: &str, out: &Path) { let compiler = Compiler::new(stage, host); let out_dir = build.stage_out(stage, host, Mode::Libstd) .join(host).join("doc"); - let rustdoc = build.tool(&compiler, "rustdoc"); - if !up_to_date(&rustdoc, &out_dir.join("std/index.html")) { - t!(fs::remove_dir_all(&out_dir)); - } + let rustdoc = build.rustdoc(&compiler); + + build.clear_if_dirty(&out_dir, &rustdoc); let mut cargo = build.cargo(stage, &compiler, Mode::Libstd, Some(host), "doc"); @@ -127,7 +127,7 @@ pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) { let compiler = Compiler::new(stage, host); let out_dir = build.stage_out(stage, host, Mode::Librustc) .join(host).join("doc"); - let rustdoc = build.tool(&compiler, "rustdoc"); + let rustdoc = build.rustdoc(&compiler); if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) { t!(fs::remove_dir_all(&out_dir)); } diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 3acd34b4e94..825cca6563c 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -275,7 +275,8 @@ impl Build { .env("RUSTC_SYSROOT", self.sysroot(stage, host)) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()) .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) - .env("RUSTDOC", self.tool(compiler, "rustdoc")); + .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) + .env("RUSTDOC_REAL", self.rustdoc(compiler)); if let Some(target) = target { cargo.env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); @@ -317,13 +318,26 @@ impl Build { } } - /// Get the specified tool next to the specified compiler + /// Get the specified tool built by the specified compiler fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf { self.stage_out(compiler.stage, compiler.host, Mode::Tool) .join(self.cargo_dir()) .join(exe(tool, compiler.host)) } + /// Get the `rustdoc` executable next to the specified compiler + fn rustdoc(&self, compiler: &Compiler) -> PathBuf { + let root = if compiler.is_snapshot(self) { + let mut rustdoc = self.rustc.clone(); + rustdoc.pop(); + rustdoc + } else { + let (stage, host) = (compiler.stage, compiler.host); + self.cargo_out(stage - 1, host, Mode::Librustc, host) + }; + root.join(exe("rustdoc", compiler.host)) + } + /// Get a `Command` which is ready to run `tool` in `stage` built for /// `host`. #[allow(dead_code)] // this will be used soon diff --git a/src/bootstrap/rustc.rs b/src/bootstrap/rustc.rs index 4e9d6da9157..d403d76bb14 100644 --- a/src/bootstrap/rustc.rs +++ b/src/bootstrap/rustc.rs @@ -8,6 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Shim which is passed to Cargo as "rustc" when running the bootstrap. +//! +//! This shim will take care of some various tasks that our build process +//! requires that Cargo can't quite do through normal configuration: +//! +//! 1. When compiling build scripts and build dependencies, we need a guaranteed +//! full standard library available. The only compiler which actually has +//! this is the snapshot, so we detect this situation and always compile with +//! the snapshot compiler. +//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling +//! (and this slightly differs based on a whether we're using a snapshot or +//! not), so we do that all here. +//! +//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of +//! switching compilers for the bootstrap and for build scripts will probably +//! never get replaced. + extern crate bootstrap; use std::env; diff --git a/src/bootstrap/rustdoc.rs b/src/bootstrap/rustdoc.rs new file mode 100644 index 00000000000..8c618196113 --- /dev/null +++ b/src/bootstrap/rustdoc.rs @@ -0,0 +1,31 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Shim which is passed to Cargo as "rustdoc" when running the bootstrap. +//! +//! See comments in `src/bootstrap/rustc.rs` for more information. + +use std::env; +use std::process::Command; + +fn main() { + let args = env::args_os().skip(1).collect::>(); + let rustdoc = env::var_os("RUSTDOC_REAL").unwrap(); + + let mut cmd = Command::new(rustdoc); + cmd.args(&args) + .arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap())) + .arg("--cfg").arg("dox"); + std::process::exit(match cmd.status() { + Ok(s) => s.code().unwrap_or(1), + Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), + }) +} + -- cgit 1.4.1-3-g733a5 From defd1b3392df2434ae67e0885cba16cdb9a2d5b4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 23:15:55 -0800 Subject: rustbuild: Add a link checker for documentation Add a script to get run which verifies that `href` links in documents are correct. We're always getting a steady stream of "fix a broken link" PRs and issue reports, and we should probably just nip them all in the bud. --- src/bootstrap/bootstrap.py | 3 +- src/bootstrap/build/check.rs | 21 +++++ src/bootstrap/build/mod.rs | 8 ++ src/bootstrap/build/step.rs | 14 +++- src/tools/linkchecker/Cargo.lock | 64 ++++++++++++++++ src/tools/linkchecker/Cargo.toml | 11 +++ src/tools/linkchecker/main.rs | 161 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 src/bootstrap/build/check.rs create mode 100644 src/tools/linkchecker/Cargo.lock create mode 100644 src/tools/linkchecker/Cargo.toml create mode 100644 src/tools/linkchecker/main.rs diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 6659894a171..5de7e6957c6 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -73,7 +73,8 @@ class RustBuild: if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): - shutil.rmtree(self.bin_root()) + if os.path.exists(self.bin_root()): + shutil.rmtree(self.bin_root()) filename = "rust-std-nightly-" + self.build + ".tar.gz" url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date() tarball = os.path.join(rustc_cache, filename) diff --git a/src/bootstrap/build/check.rs b/src/bootstrap/build/check.rs new file mode 100644 index 00000000000..19293e80217 --- /dev/null +++ b/src/bootstrap/build/check.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::process::Command; + +use build::{Build, Compiler}; + +pub fn linkcheck(build: &Build, stage: u32, host: &str) { + println!("Linkcheck stage{} ({})", stage, host); + let compiler = Compiler::new(stage, host); + let linkchecker = build.tool(&compiler, "linkchecker"); + build.run(Command::new(&linkchecker) + .arg(build.out.join(host).join("doc"))); +} diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 825cca6563c..9f24fba5843 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -30,6 +30,7 @@ macro_rules! t { mod cc; mod channel; +mod check; mod clean; mod compile; mod config; @@ -171,6 +172,9 @@ impl Build { Rustc { stage } => { compile::assemble_rustc(self, stage, target.target); } + ToolLinkchecker { stage } => { + compile::tool(self, stage, target.target, "linkchecker"); + } ToolRustbook { stage } => { compile::tool(self, stage, target.target, "rustbook"); } @@ -195,6 +199,10 @@ impl Build { doc::rustc(self, stage, target.target, &doc_out); } + CheckLinkcheck { stage } => { + check::linkcheck(self, stage, target.target); + } + Doc { .. } | // pseudo-steps Check { .. } => {} } diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index 23c678df9ac..7921edcff55 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -46,6 +46,7 @@ macro_rules! targets { }), // Various tools that we can build as part of the build. + (tool_linkchecker, ToolLinkchecker { stage: u32 }), (tool_rustbook, ToolRustbook { stage: u32 }), // Steps for long-running native builds. Ideally these wouldn't @@ -71,6 +72,7 @@ macro_rules! targets { // Steps for running tests. The 'check' target is just a pseudo // target to depend on a bunch of others. (check, Check { stage: u32, compiler: Compiler<'a> }), + (check_linkcheck, CheckLinkcheck { stage: u32 }), } } } @@ -200,6 +202,8 @@ fn add_steps<'a>(build: &'a Build, } targets!(add_step); + + panic!("unknown step: {}", step); } } @@ -273,7 +277,15 @@ impl<'a> Step<'a> { self.doc_std(stage)] } Source::Check { stage, compiler: _ } => { - vec![] + vec![self.check_linkcheck(stage)] + } + Source::CheckLinkcheck { stage } => { + vec![self.tool_linkchecker(stage), self.doc(stage)] + } + + Source::ToolLinkchecker { stage } => { + vec![self.libstd(stage, self.compiler(stage))] + } Source::ToolRustbook { stage } => { vec![self.librustc(stage, self.compiler(stage))] } diff --git a/src/tools/linkchecker/Cargo.lock b/src/tools/linkchecker/Cargo.lock new file mode 100644 index 00000000000..8e94137d213 --- /dev/null +++ b/src/tools/linkchecker/Cargo.lock @@ -0,0 +1,64 @@ +[root] +name = "linkchecker" +version = "0.1.0" +dependencies = [ + "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "matches" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uuid" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml new file mode 100644 index 00000000000..29fc78a65e9 --- /dev/null +++ b/src/tools/linkchecker/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "linkchecker" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] +url = "0.5" + +[[bin]] +name = "linkchecker" +path = "main.rs" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs new file mode 100644 index 00000000000..e5e88081bc4 --- /dev/null +++ b/src/tools/linkchecker/main.rs @@ -0,0 +1,161 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Script to check the validity of `href` links in our HTML documentation. +//! +//! In the past we've been quite error prone to writing in broken links as most +//! of them are manually rather than automatically added. As files move over +//! time or apis change old links become stale or broken. The purpose of this +//! script is to check all relative links in our documentation to make sure they +//! actually point to a valid place. +//! +//! Currently this doesn't actually do any HTML parsing or anything fancy like +//! that, it just has a simple "regex" to search for `href` tags. These values +//! are then translated to file URLs if possible and then the destination is +//! asserted to exist. +//! +//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc, +//! but this should catch the majority of "broken link" cases. + +extern crate url; + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::path::Path; + +use url::{Url, UrlParser}; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +fn main() { + let docs = env::args().nth(1).unwrap(); + let docs = env::current_dir().unwrap().join(docs); + let mut url = Url::from_file_path(&docs).unwrap(); + let mut errors = false; + walk(&docs, &docs, &mut url, &mut errors); + if errors { + panic!("found some broken links"); + } +} + +fn walk(root: &Path, dir: &Path, url: &mut Url, errors: &mut bool) { + for entry in t!(dir.read_dir()).map(|e| t!(e)) { + let path = entry.path(); + let kind = t!(entry.file_type()); + url.path_mut().unwrap().push(entry.file_name().into_string().unwrap()); + if kind.is_dir() { + walk(root, &path, url, errors); + } else { + check(root, &path, url, errors); + } + url.path_mut().unwrap().pop(); + } +} + +fn check(root: &Path, file: &Path, base: &Url, errors: &mut bool) { + // ignore js files as they are not prone to errors as the rest of the + // documentation is and they otherwise bring up false positives. + if file.extension().and_then(|s| s.to_str()) == Some("js") { + return + } + + let pretty_file = file.strip_prefix(root).unwrap_or(file); + + // Unfortunately we're not 100% full of valid links today to we need a few + // whitelists to get this past `make check` today. + if let Some(path) = pretty_file.to_str() { + // FIXME(#32129) + if path == "std/string/struct.String.html" { + return + } + // FIXME(#32130) + if path.contains("btree_set/struct.BTreeSet.html") || + path == "collections/struct.BTreeSet.html" { + return + } + // FIXME(#31948) + if path.contains("ParseFloatError") { + return + } + + // currently + if path == "std/sys/ext/index.html" { + return + } + + // weird reexports, but this module is on its way out, so chalk it up to + // "rustdoc weirdness" and move on from there + if path.contains("scoped_tls") { + return + } + } + + let mut parser = UrlParser::new(); + parser.base_url(base); + let mut contents = String::new(); + if t!(File::open(file)).read_to_string(&mut contents).is_err() { + return + } + + for (i, mut line) in contents.lines().enumerate() { + // Search for anything that's the regex 'href[ ]*=[ ]*".*?"' + while let Some(j) = line.find(" href") { + let rest = &line[j + 5..]; + line = rest; + let pos_equals = match rest.find("=") { + Some(i) => i, + None => continue, + }; + if rest[..pos_equals].trim_left_matches(" ") != "" { + continue + } + let rest = &rest[pos_equals + 1..]; + let pos_quote = match rest.find("\"").or_else(|| rest.find("'")) { + Some(i) => i, + None => continue, + }; + if rest[..pos_quote].trim_left_matches(" ") != "" { + continue + } + let rest = &rest[pos_quote + 1..]; + let url = match rest.find("\"").or_else(|| rest.find("'")) { + Some(i) => &rest[..i], + None => continue, + }; + + // Once we've plucked out the URL, parse it using our base url and + // then try to extract a file path. If either if these fail then we + // just keep going. + let parsed_url = match parser.parse(url) { + Ok(url) => url, + Err(..) => continue, + }; + let path = match parsed_url.to_file_path() { + Ok(path) => path, + Err(..) => continue, + }; + + // Alright, if we've found a file name then this file had better + // exist! If it doesn't then we register and print an error. + if !path.exists() { + *errors = true; + print!("{}:{}: broken link - ", pretty_file.display(), i + 1); + let pretty_path = path.strip_prefix(root).unwrap_or(&path); + println!("{}", pretty_path.display()); + } + } + } +} -- cgit 1.4.1-3-g733a5 From 16fefc5ead7d3338acf80f225f0f256a286345c5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 23:21:05 -0800 Subject: rustbuild: Fix stage1 rustdoc Just always build stage1 rustdoc, it's really not that much more to build as it's essentially just one library. --- src/bootstrap/build/compile.rs | 7 +------ src/bootstrap/build/doc.rs | 2 +- src/bootstrap/build/mod.rs | 5 +---- src/librustdoc/html/render.rs | 2 +- src/rustc/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/build/compile.rs b/src/bootstrap/build/compile.rs index c4d6e66b878..0a293579cf6 100644 --- a/src/bootstrap/build/compile.rs +++ b/src/bootstrap/build/compile.rs @@ -141,15 +141,10 @@ pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str, let mut cargo = build.cargo(stage, compiler, Mode::Librustc, Some(target), "build"); - cargo.arg("--features").arg(build.rustc_features(stage)) + cargo.arg("--features").arg(build.rustc_features()) .arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")); - // In stage0 we may not need to build as many executables - if stage == 0 { - cargo.arg("--bin").arg("rustc"); - } - // Set some configuration variables picked up by build scripts and // the compiler alike cargo.env("CFG_RELEASE", &build.release) diff --git a/src/bootstrap/build/doc.rs b/src/bootstrap/build/doc.rs index 917860962c9..ce79a605259 100644 --- a/src/bootstrap/build/doc.rs +++ b/src/bootstrap/build/doc.rs @@ -135,7 +135,7 @@ pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) { "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")) - .arg("--features").arg(build.rustc_features(stage)); + .arg("--features").arg(build.rustc_features()); build.run(&mut cargo); cp_r(&out_dir, out) } diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 9f24fba5843..b4fb67beaf9 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -379,14 +379,11 @@ impl Build { } /// Get the space-separated set of activated features for the compiler. - fn rustc_features(&self, stage: u32) -> String { + fn rustc_features(&self) -> String { let mut features = String::new(); if self.config.use_jemalloc { features.push_str(" jemalloc"); } - if stage > 0 { - features.push_str(" rustdoc"); - } return features } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2cb2b299e40..eb2d7868945 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1454,7 +1454,7 @@ impl<'a> Item<'a> { // has anchors for the line numbers that we're linking to. } else if self.item.def_id.is_local() { self.cx.local_sources.get(&PathBuf::from(&self.item.source.filename)).map(|path| { - format!("{root}src/{krate}/{path}.html#{href}", + format!("{root}src/{krate}/{path}#{href}", root = self.cx.root_path, krate = self.cx.layout.krate, path = path, diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml index f1abf35cbc0..7431c35efba 100644 --- a/src/rustc/Cargo.toml +++ b/src/rustc/Cargo.toml @@ -25,7 +25,7 @@ debug-assertions = false [dependencies] rustc_back = { path = "../librustc_back" } rustc_driver = { path = "../librustc_driver" } -rustdoc = { path = "../librustdoc", optional = true } +rustdoc = { path = "../librustdoc" } [features] jemalloc = ["rustc_back/jemalloc"] -- cgit 1.4.1-3-g733a5 From 73db76015e39d18950d654d3a32ba9053261242f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Mar 2016 23:55:52 -0800 Subject: doc: Fix a bunch of broken links A few categories: * Links into compiler docs were just all removed as we're not generating compiler docs. * Move up one more level to forcibly go to std docs to fix inlined documentation across the facade crates. --- src/doc/book/choosing-your-guarantees.md | 3 +- src/doc/book/compiler-plugins.md | 57 +++++++++------------- src/doc/guide-plugins.md | 2 +- src/doc/style/README.md | 2 +- .../style/features/functions-and-methods/input.md | 2 +- src/doc/style/style/naming/README.md | 2 +- src/libcollections/btree/set.rs | 4 +- src/libcollections/lib.rs | 8 +++ src/libcollections/slice.rs | 2 +- src/libcollections/str.rs | 2 +- src/libcollections/string.rs | 54 ++++++++++---------- src/libcore/any.rs | 2 +- src/libcore/char.rs | 18 +++---- src/libcore/iter.rs | 18 +++---- src/libcore/macros.rs | 8 +-- src/libcore/num/mod.rs | 6 +-- src/libcore/slice.rs | 1 + src/libcore/str/mod.rs | 36 +++++++------- src/librand/lib.rs | 1 + src/librustc_unicode/char.rs | 12 ++--- src/libstd/num/f32.rs | 2 +- src/libstd/num/f64.rs | 2 +- src/libstd/primitive_docs.rs | 30 ++++++------ 23 files changed, 135 insertions(+), 139 deletions(-) diff --git a/src/doc/book/choosing-your-guarantees.md b/src/doc/book/choosing-your-guarantees.md index f2b92e6dec4..50350213074 100644 --- a/src/doc/book/choosing-your-guarantees.md +++ b/src/doc/book/choosing-your-guarantees.md @@ -204,7 +204,7 @@ borrow checker. Generally we know that such mutations won't happen in a nested f to check. For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things -simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the Rust compiler internals +simpler. For example, a lot of the maps in the `ctxt` struct in the Rust compiler internals are inside this wrapper. These are only modified once (during creation, which is not right after initialization) or a couple of times in well-separated places. However, since this struct is pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps @@ -235,7 +235,6 @@ At runtime each borrow causes a modification/check of the refcount. [cell-mod]: ../std/cell/ [cell]: ../std/cell/struct.Cell.html [refcell]: ../std/cell/struct.RefCell.html -[ctxt]: ../rustc/middle/ty/struct.ctxt.html # Synchronous types diff --git a/src/doc/book/compiler-plugins.md b/src/doc/book/compiler-plugins.md index 800be13a243..1af05bfea19 100644 --- a/src/doc/book/compiler-plugins.md +++ b/src/doc/book/compiler-plugins.md @@ -8,12 +8,12 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc. A plugin is a dynamic library crate with a designated *registrar* function that registers extensions with `rustc`. Other crates can load these extensions using the crate attribute `#![plugin(...)]`. See the -[`rustc_plugin`](../rustc_plugin/index.html) documentation for more about the +`rustc_plugin` documentation for more about the mechanics of defining and loading a plugin. If present, arguments passed as `#![plugin(foo(... args ...))]` are not interpreted by rustc itself. They are provided to the plugin through the -`Registry`'s [`args` method](../rustc_plugin/registry/struct.Registry.html#method.args). +`Registry`'s `args` method. In the vast majority of cases, a plugin should *only* be used through `#![plugin]` and not through an `extern crate` item. Linking a plugin would @@ -30,7 +30,7 @@ of a library. Plugins can extend Rust's syntax in various ways. One kind of syntax extension is the procedural macro. These are invoked the same way as [ordinary macros](macros.html), but the expansion is performed by arbitrary Rust -code that manipulates [syntax trees](../syntax/ast/index.html) at +code that manipulates syntax trees at compile time. Let's write a plugin @@ -120,11 +120,8 @@ The advantages over a simple `fn(&str) -> u32` are: In addition to procedural macros, you can define new [`derive`](../reference.html#derive)-like attributes and other kinds of -extensions. See -[`Registry::register_syntax_extension`](../rustc_plugin/registry/struct.Registry.html#method.register_syntax_extension) -and the [`SyntaxExtension` -enum](https://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For -a more involved macro example, see +extensions. See `Registry::register_syntax_extension` and the `SyntaxExtension` +enum. For a more involved macro example, see [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs). @@ -132,7 +129,7 @@ a more involved macro example, see Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable. -You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into +You can use `syntax::parse` to turn token trees into higher-level syntax elements like expressions: ```ignore @@ -148,30 +145,21 @@ Looking through [`libsyntax` parser code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs) will give you a feel for how the parsing infrastructure works. -Keep the [`Span`s](../syntax/codemap/struct.Span.html) of -everything you parse, for better error reporting. You can wrap -[`Spanned`](../syntax/codemap/struct.Spanned.html) around -your custom data structures. - -Calling -[`ExtCtxt::span_fatal`](../syntax/ext/base/struct.ExtCtxt.html#method.span_fatal) -will immediately abort compilation. It's better to instead call -[`ExtCtxt::span_err`](../syntax/ext/base/struct.ExtCtxt.html#method.span_err) -and return -[`DummyResult`](../syntax/ext/base/struct.DummyResult.html), -so that the compiler can continue and find further errors. - -To print syntax fragments for debugging, you can use -[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together -with -[`syntax::print::pprust::*_to_string`](https://doc.rust-lang.org/syntax/print/pprust/index.html#functions). - -The example above produced an integer literal using -[`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize). +Keep the `Span`s of everything you parse, for better error reporting. You can +wrap `Spanned` around your custom data structures. + +Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to +instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler +can continue and find further errors. + +To print syntax fragments for debugging, you can use `span_note` together with +`syntax::print::pprust::*_to_string`. + +The example above produced an integer literal using `AstBuilder::expr_usize`. As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of -[quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and -very rough around the edges. However, the implementation may be a good -starting point for an improved quasiquote as an ordinary plugin library. +quasiquote macros. They are undocumented and very rough around the edges. +However, the implementation may be a good starting point for an improved +quasiquote as an ordinary plugin library. # Lint plugins @@ -239,12 +227,11 @@ foo.rs:4 fn lintme() { } The components of a lint plugin are: -* one or more `declare_lint!` invocations, which define static - [`Lint`](../rustc/lint/struct.Lint.html) structs; +* one or more `declare_lint!` invocations, which define static `Lint` structs; * a struct holding any state needed by the lint pass (here, none); -* a [`LintPass`](../rustc/lint/trait.LintPass.html) +* a `LintPass` implementation defining how to check each syntax element. A single `LintPass` may call `span_lint` for several different `Lint`s, but should register them all through the `get_lints` method. diff --git a/src/doc/guide-plugins.md b/src/doc/guide-plugins.md index d6495d02e11..742433b99ac 100644 --- a/src/doc/guide-plugins.md +++ b/src/doc/guide-plugins.md @@ -1,4 +1,4 @@ % The (old) Rust Compiler Plugins Guide This content has moved into -[the Rust Programming Language book](book/plugins.html). +[the Rust Programming Language book](book/compiler-plugins.html). diff --git a/src/doc/style/README.md b/src/doc/style/README.md index 5ab1a1d9c10..8d837d1a1a9 100644 --- a/src/doc/style/README.md +++ b/src/doc/style/README.md @@ -53,7 +53,7 @@ This document is broken into four parts: cross-cutting topic, starting with [Ownership and resources](ownership/README.md). -* **[APIs for a changing Rust](changing/README.md)** +* **APIs for a changing Rust** discusses the forward-compatibility hazards, especially those that interact with the pre-1.0 library stabilization process. diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md index 9ea1d218161..9b243bc72ef 100644 --- a/src/doc/style/features/functions-and-methods/input.md +++ b/src/doc/style/features/functions-and-methods/input.md @@ -76,7 +76,7 @@ needs to make about its arguments. On the other hand, generics can make it more difficult to read and understand a function's signature. Aim for "natural" parameter types that a neither overly concrete nor overly abstract. See the discussion on -[traits](../../traits/README.md) for more guidance. +[traits](../traits/README.md) for more guidance. #### Minimizing ownership assumptions: diff --git a/src/doc/style/style/naming/README.md b/src/doc/style/style/naming/README.md index 9d78721ad36..2106f32fafa 100644 --- a/src/doc/style/style/naming/README.md +++ b/src/doc/style/style/naming/README.md @@ -101,7 +101,7 @@ The convention for a field `foo: T` is: here may take `&T` or some other type, depending on the context.) Note that this convention is about getters/setters on ordinary data types, *not* -on [builder objects](../ownership/builders.html). +on [builder objects](../../ownership/builders.html). ### Escape hatches [FIXME] diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 1cd50c2dcbe..a2ad58afc7f 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -34,8 +34,8 @@ use Bound; /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// -/// [`BTreeMap`]: ../struct.BTreeMap.html -/// [`Ord`]: ../../core/cmp/trait.Ord.html +/// [`BTreeMap`]: struct.BTreeMap.html +/// [`Ord`]: ../../std/cmp/trait.Ord.html /// [`Cell`]: ../../std/cell/struct.Cell.html /// [`RefCell`]: ../../std/cell/struct.RefCell.html #[derive(Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 922e1b0fc5d..cef6edf68ee 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -71,13 +71,21 @@ extern crate std; #[cfg(test)] extern crate test; +#[doc(no_inline)] pub use binary_heap::BinaryHeap; +#[doc(no_inline)] pub use btree_map::BTreeMap; +#[doc(no_inline)] pub use btree_set::BTreeSet; +#[doc(no_inline)] pub use linked_list::LinkedList; +#[doc(no_inline)] pub use enum_set::EnumSet; +#[doc(no_inline)] pub use vec_deque::VecDeque; +#[doc(no_inline)] pub use string::String; +#[doc(no_inline)] pub use vec::Vec; // Needed for the vec! macro diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 1446d00b9ea..69a9899d82b 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -78,7 +78,7 @@ //! * Further methods that return iterators are `.split()`, `.splitn()`, //! `.chunks()`, `.windows()` and more. //! -//! *[See also the slice primitive type](../primitive.slice.html).* +//! *[See also the slice primitive type](../../std/primitive.slice.html).* #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 5789cd8edfc..9798e323a61 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,7 +10,7 @@ //! Unicode string slices. //! -//! *[See also the `str` primitive type](../primitive.str.html).* +//! *[See also the `str` primitive type](../../std/primitive.str.html).* #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index cae6520bdb2..02190d11b42 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -79,7 +79,7 @@ use boxed::Box; /// contents of the string. It has a close relationship with its borrowed /// counterpart, the primitive [`str`]. /// -/// [`str`]: ../primitive.str.html +/// [`str`]: ../../std/primitive.str.html /// /// # Examples /// @@ -99,7 +99,7 @@ use boxed::Box; /// hello.push_str("orld!"); /// ``` /// -/// [`char`]: ../primitive.char.html +/// [`char`]: ../../std/primitive.char.html /// [`push()`]: #method.push /// [`push_str()`]: #method.push_str /// @@ -131,7 +131,7 @@ use boxed::Box; /// println!("The first letter of s is {}", s[0]); // ERROR!!! /// ``` /// -/// [`OsString`]: ../ffi/struct.OsString.html +/// [`OsString`]: ../../std/ffi/struct.OsString.html /// /// Indexing is intended to be a constant-time operation, but UTF-8 encoding /// does not allow us to do this. Furtheremore, it's not clear what sort of @@ -156,8 +156,8 @@ use boxed::Box; /// takes_str(&s); /// ``` /// -/// [`&str`]: ../primitive.str.html -/// [`Deref`]: ../ops/trait.Deref.html +/// [`&str`]: ../../std/primitive.str.html +/// [`Deref`]: ../../std/ops/trait.Deref.html /// /// This will create a [`&str`] from the `String` and pass it in. This /// conversion is very inexpensive, and so generally, functions will accept @@ -280,10 +280,10 @@ pub struct String { /// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error` /// through the [`utf8_error()`] method. /// -/// [`Utf8Error`]: ../str/struct.Utf8Error.html -/// [`std::str`]: ../str/index.html -/// [`u8`]: ../primitive.u8.html -/// [`&str`]: ../primitive.str.html +/// [`Utf8Error`]: ../../std/str/struct.Utf8Error.html +/// [`std::str`]: ../../std/str/index.html +/// [`u8`]: ../../std/primitive.u8.html +/// [`&str`]: ../../std/primitive.str.html /// [`utf8_error()`]: #method.utf8_error /// /// # Examples @@ -414,9 +414,9 @@ impl String { /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that /// the bytes are valid UTF-8, and then does the conversion. /// - /// [`&str`]: ../primitive.str.html - /// [`u8`]: ../primitive.u8.html - /// [`Vec`]: ../vec/struct.Vec.html + /// [`&str`]: ../../std/primitive.str.html + /// [`u8`]: ../../std/primitive.u8.html + /// [`Vec`]: ../../std/vec/struct.Vec.html /// /// If you are sure that the byte slice is valid UTF-8, and you don't want /// to incur the overhead of the validity check, there is an unsafe version @@ -431,7 +431,7 @@ impl String { /// If you need a `&str` instead of a `String`, consider /// [`str::from_utf8()`]. /// - /// [`str::from_utf8()`]: ../str/fn.from_utf8.html + /// [`str::from_utf8()`]: ../../std/str/fn.from_utf8.html /// /// # Errors /// @@ -488,8 +488,8 @@ impl String { /// `from_utf8_lossy()` will replace any invalid UTF-8 sequences with /// `U+FFFD REPLACEMENT CHARACTER`, which looks like this: � /// - /// [`u8`]: ../primitive.u8.html - /// [byteslice]: ../primitive.slice.html + /// [`u8`]: ../../std/primitive.u8.html + /// [byteslice]: ../../std/primitive.slice.html /// /// If you are sure that the byte slice is valid UTF-8, and you don't want /// to incur the overhead of the conversion, there is an unsafe version @@ -504,7 +504,7 @@ impl String { /// it's already valid UTF-8, we don't need a new allocation. This return /// type allows us to handle both cases. /// - /// [`Cow<'a, str>`]: ../borrow/enum.Cow.html + /// [`Cow<'a, str>`]: ../../std/borrow/enum.Cow.html /// /// # Examples /// @@ -1014,7 +1014,7 @@ impl String { /// Panics if `new_len` > current length, or if `new_len` does not lie on a /// [`char`] boundary. /// - /// [`char`]: ../primitive.char.html + /// [`char`]: ../../std/primitive.char.html /// /// # Examples /// @@ -1076,7 +1076,7 @@ impl String { /// Panics if `idx` is larger than or equal to the `String`'s length, /// or if it does not lie on a [`char`] boundary. /// - /// [`char`]: ../primitive.char.html + /// [`char`]: ../../std/primitive.char.html /// /// # Examples /// @@ -1116,7 +1116,7 @@ impl String { /// Panics if `idx` is larger than the `String`'s length, or if it does not /// lie on a [`char`] boundary. /// - /// [`char`]: ../primitive.char.html + /// [`char`]: ../../std/primitive.char.html /// /// # Examples /// @@ -1255,7 +1255,7 @@ impl String { /// Panics if the starting point or end point do not lie on a [`char`] /// boundary, or if they're out of bounds. /// - /// [`char`]: ../primitive.char.html + /// [`char`]: ../../std/primitive.char.html /// /// # Examples /// @@ -1353,10 +1353,10 @@ impl FromUtf8Error { /// an analogue to `FromUtf8Error`. See its documentation for more details /// on using it. /// - /// [`Utf8Error`]: ../str/struct.Utf8Error.html - /// [`std::str`]: ../str/index.html - /// [`u8`]: ../primitive.u8.html - /// [`&str`]: ../primitive.str.html + /// [`Utf8Error`]: ../../std/str/struct.Utf8Error.html + /// [`std::str`]: ../../std/str/index.html + /// [`u8`]: ../../std/primitive.u8.html + /// [`&str`]: ../../std/primitive.str.html /// /// # Examples /// @@ -1695,9 +1695,9 @@ impl ops::DerefMut for String { /// [`String`] without error, this type will never actually be returned. As /// such, it is only here to satisfy said signature, and is useless otherwise. /// -/// [`FromStr`]: ../str/trait.FromStr.html +/// [`FromStr`]: ../../std/str/trait.FromStr.html /// [`String`]: struct.String.html -/// [`from_str()`]: ../str/trait.FromStr.html#tymethod.from_str +/// [`from_str()`]: ../../std/str/trait.FromStr.html#tymethod.from_str #[stable(feature = "str_parse_error", since = "1.5.0")] #[derive(Copy)] pub enum ParseError {} @@ -1749,7 +1749,7 @@ impl Eq for ParseError {} /// [`Display`] should be implemented instead, and you get the `ToString` /// implementation for free. /// -/// [`Display`]: ../fmt/trait.Display.html +/// [`Display`]: ../../std/fmt/trait.Display.html #[stable(feature = "rust1", since = "1.0.0")] pub trait ToString { /// Converts the given value to a `String`. diff --git a/src/libcore/any.rs b/src/libcore/any.rs index cb9bf935cdb..dfd2ba9154d 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -22,7 +22,7 @@ //! Note that &Any is limited to testing whether a value is of a specified //! concrete type, and cannot be used to test whether a type implements a trait. //! -//! [`Box`]: ../boxed/struct.Box.html +//! [`Box`]: ../../std/boxed/struct.Box.html //! //! # Examples //! diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 0c3807d8ca0..a23b303f4ba 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -69,7 +69,7 @@ const MAX_THREE_B: u32 = 0x10000; /// Point], but only ones within a certain range. `MAX` is the highest valid /// code point that's a valid [Unicode Scalar Value]. /// -/// [`char`]: ../primitive.char.html +/// [`char`]: ../../std/primitive.char.html /// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value /// [Code Point]: http://www.unicode.org/glossary/#code_point #[stable(feature = "rust1", since = "1.0.0")] @@ -91,8 +91,8 @@ pub const MAX: char = '\u{10ffff}'; /// [`char`]s. `from_u32()` will return `None` if the input is not a valid value /// for a [`char`]. /// -/// [`char`]: ../primitive.char.html -/// [`u32`]: ../primitive.u32.html +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html /// [`as`]: ../../book/casting-between-types.html#as /// /// For an unsafe version of this function which ignores these checks, see @@ -148,8 +148,8 @@ pub fn from_u32(i: u32) -> Option { /// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to /// [`char`], possibly creating an invalid one. /// -/// [`char`]: ../primitive.char.html -/// [`u32`]: ../primitive.u32.html +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html /// [`as`]: ../../book/casting-between-types.html#as /// /// # Safety @@ -414,8 +414,8 @@ pub fn encode_utf16_raw(mut ch: u32, dst: &mut [u16]) -> Option { /// This `struct` is created by the [`escape_unicode()`] method on [`char`]. See /// its documentation for more. /// -/// [`escape_unicode()`]: ../primitive.char.html#method.escape_unicode -/// [`char`]: ../primitive.char.html +/// [`escape_unicode()`]: ../../std/primitive.char.html#method.escape_unicode +/// [`char`]: ../../std/primitive.char.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeUnicode { @@ -494,8 +494,8 @@ impl Iterator for EscapeUnicode { /// This `struct` is created by the [`escape_default()`] method on [`char`]. See /// its documentation for more. /// -/// [`escape_default()`]: ../primitive.char.html#method.escape_default -/// [`char`]: ../primitive.char.html +/// [`escape_default()`]: ../../std/primitive.char.html#method.escape_default +/// [`char`]: ../../std/primitive.char.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index fb8eda820f5..06821ff94f7 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -65,7 +65,7 @@ //! //! [`Iterator`]: trait.Iterator.html //! [`next()`]: trait.Iterator.html#tymethod.next -//! [`Option`]: ../option/enum.Option.html +//! [`Option`]: ../../std/option/enum.Option.html //! //! # The three forms of iteration //! @@ -804,7 +804,7 @@ pub trait Iterator { /// closure returns `None`, it will try again, and call the closure on the /// next element, seeing if it will return `Some`. /// - /// [`Option`]: ../option/enum.Option.html + /// [`Option`]: ../../std/option/enum.Option.html /// /// Why `filter_map()` and not just [`filter()`].[`map()`]? The key is in this /// part: @@ -866,7 +866,7 @@ pub trait Iterator { /// different sized integer, the [`zip()`] function provides similar /// functionality. /// - /// [`usize`]: ../primitive.usize.html + /// [`usize`]: ../../std/primitive.usize.html /// [`zip()`]: #method.zip /// /// # Overflow Behavior @@ -875,7 +875,7 @@ pub trait Iterator { /// [`usize::MAX`] elements either produces the wrong result or panics. If /// debug assertions are enabled, a panic is guaranteed. /// - /// [`usize::MAX`]: ../usize/constant.MAX.html + /// [`usize::MAX`]: ../../std/usize/constant.MAX.html /// /// # Panics /// @@ -1151,7 +1151,7 @@ pub trait Iterator { /// iterator and the return value from the closure, an [`Option`], is /// yielded by the iterator. /// - /// [`Option`]: ../option/enum.Option.html + /// [`Option`]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -1385,9 +1385,9 @@ pub trait Iterator { /// be thought of as single `Result, E>`. See the examples /// below for more. /// - /// [`String`]: ../string/struct.String.html - /// [`Result`]: ../result/enum.Result.html - /// [`char`]: ../primitive.char.html + /// [`String`]: ../../std/string/struct.String.html + /// [`Result`]: ../../std/result/enum.Result.html + /// [`char`]: ../../std/primitive.char.html /// /// Because `collect()` is so general, it can cause problems with type /// inference. As such, `collect()` is one of the few times you'll see @@ -1412,7 +1412,7 @@ pub trait Iterator { /// Note that we needed the `: Vec` on the left-hand side. This is because /// we could collect into, for example, a [`VecDeque`] instead: /// - /// [`VecDeque`]: ../collections/struct.VecDeque.html + /// [`VecDeque`]: ../../std/collections/struct.VecDeque.html /// /// ``` /// use std::collections::VecDeque; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 154ca30c62d..f923668688b 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -206,8 +206,8 @@ macro_rules! try { /// /// See [`std::fmt`][fmt] for more information on format syntax. /// -/// [fmt]: fmt/index.html -/// [write]: io/trait.Write.html +/// [fmt]: ../std/fmt/index.html +/// [write]: ../std/io/trait.Write.html /// /// # Examples /// @@ -232,8 +232,8 @@ macro_rules! write { /// /// See [`std::fmt`][fmt] for more information on format syntax. /// -/// [fmt]: fmt/index.html -/// [write]: io/trait.Write.html +/// [fmt]: ../std/fmt/index.html +/// [write]: ../std/io/trait.Write.html /// /// # Examples /// diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ed370bb9164..0b306c810b1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2179,8 +2179,8 @@ impl usize { /// This `enum` is used as the return type for [`f32::classify()`] and [`f64::classify()`]. See /// their documentation for more. /// -/// [`f32::classify()`]: ../primitive.f32.html#method.classify -/// [`f64::classify()`]: ../primitive.f64.html#method.classify +/// [`f32::classify()`]: ../../std/primitive.f32.html#method.classify +/// [`f64::classify()`]: ../../std/primitive.f64.html#method.classify #[derive(Copy, Clone, PartialEq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum FpCategory { @@ -2411,7 +2411,7 @@ fn from_str_radix(src: &str, radix: u32) /// This error is used as the error type for the `from_str_radix()` functions /// on the primitive integer types, such as [`i8::from_str_radix()`]. /// -/// [`i8::from_str_radix()`]: ../std/primitive.i8.html#method.from_str_radix +/// [`i8::from_str_radix()`]: ../../std/primitive.i8.html#method.from_str_radix #[derive(Debug, Clone, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseIntError { kind: IntErrorKind } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 8acd0c8f2cf..e59e8567d5b 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -908,6 +908,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} /// An internal abstraction over the splitting iterators, so that /// splitn, splitn_mut etc can be implemented once. +#[doc(hidden)] trait SplitIter: DoubleEndedIterator { /// Mark the underlying iterator as complete, extracting the remaining /// portion of the slice. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 79f925aaab0..4480e7095e4 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -42,8 +42,8 @@ pub mod pattern; /// [`str`]'s [`parse()`] method. See [`parse()`]'s documentation for examples. /// /// [`from_str()`]: #tymethod.from_str -/// [`str`]: ../primitive.str.html -/// [`parse()`]: ../primitive.str.html#method.parse +/// [`str`]: ../../std/primitive.str.html +/// [`parse()`]: ../../std/primitive.str.html#method.parse #[stable(feature = "rust1", since = "1.0.0")] pub trait FromStr: Sized { /// The associated error which can be returned from parsing. @@ -60,7 +60,7 @@ pub trait FromStr: Sized { /// /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`: /// - /// [ithirtytwo]: ../primitive.i32.html + /// [ithirtytwo]: ../../std/primitive.i32.html /// /// ``` /// use std::str::FromStr; @@ -182,7 +182,7 @@ impl Utf8Error { /// If you need a `String` instead of a `&str`, consider /// [`String::from_utf8()`][string]. /// -/// [string]: ../string/struct.String.html#method.from_utf8 +/// [string]: ../../std/string/struct.String.html#method.from_utf8 /// /// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of /// it, this function is one way to have a stack-allocated string. There is @@ -322,7 +322,7 @@ Section: Iterators /// /// Created with the method [`chars()`]. /// -/// [`chars()`]: ../primitive.str.html#method.chars +/// [`chars()`]: ../../std/primitive.str.html#method.chars #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { @@ -531,7 +531,7 @@ impl<'a> CharIndices<'a> { /// /// Created with the method [`bytes()`]. /// -/// [`bytes()`]: ../primitive.str.html#method.bytes +/// [`bytes()`]: ../../std/primitive.str.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Bytes<'a>(Cloned>); @@ -816,12 +816,12 @@ generate_pattern_iterators! { forward: /// Created with the method [`split()`]. /// - /// [`split()`]: ../primitive.str.html#method.split + /// [`split()`]: ../../std/primitive.str.html#method.split struct Split; reverse: /// Created with the method [`rsplit()`]. /// - /// [`rsplit()`]: ../primitive.str.html#method.rsplit + /// [`rsplit()`]: ../../std/primitive.str.html#method.rsplit struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -834,12 +834,12 @@ generate_pattern_iterators! { forward: /// Created with the method [`split_terminator()`]. /// - /// [`split_terminator()`]: ../primitive.str.html#method.split_terminator + /// [`split_terminator()`]: ../../std/primitive.str.html#method.split_terminator struct SplitTerminator; reverse: /// Created with the method [`rsplit_terminator()`]. /// - /// [`rsplit_terminator()`]: ../primitive.str.html#method.rsplit_terminator + /// [`rsplit_terminator()`]: ../../std/primitive.str.html#method.rsplit_terminator struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -884,12 +884,12 @@ generate_pattern_iterators! { forward: /// Created with the method [`splitn()`]. /// - /// [`splitn()`]: ../primitive.str.html#method.splitn + /// [`splitn()`]: ../../std/primitive.str.html#method.splitn struct SplitN; reverse: /// Created with the method [`rsplitn()`]. /// - /// [`rsplitn()`]: ../primitive.str.html#method.rsplitn + /// [`rsplitn()`]: ../../std/primitive.str.html#method.rsplitn struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -926,12 +926,12 @@ generate_pattern_iterators! { forward: /// Created with the method [`match_indices()`]. /// - /// [`match_indices()`]: ../primitive.str.html#method.match_indices + /// [`match_indices()`]: ../../std/primitive.str.html#method.match_indices struct MatchIndices; reverse: /// Created with the method [`rmatch_indices()`]. /// - /// [`rmatch_indices()`]: ../primitive.str.html#method.rmatch_indices + /// [`rmatch_indices()`]: ../../std/primitive.str.html#method.rmatch_indices struct RMatchIndices; stability: #[stable(feature = "str_match_indices", since = "1.5.0")] @@ -970,12 +970,12 @@ generate_pattern_iterators! { forward: /// Created with the method [`matches()`]. /// - /// [`matches()`]: ../primitive.str.html#method.matches + /// [`matches()`]: ../../std/primitive.str.html#method.matches struct Matches; reverse: /// Created with the method [`rmatches()`]. /// - /// [`rmatches()`]: ../primitive.str.html#method.rmatches + /// [`rmatches()`]: ../../std/primitive.str.html#method.rmatches struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] @@ -986,7 +986,7 @@ generate_pattern_iterators! { /// Created with the method [`lines()`]. /// -/// [`lines()`]: ../primitive.str.html#method.lines +/// [`lines()`]: ../../std/primitive.str.html#method.lines #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Lines<'a>(Map, LinesAnyMap>); @@ -1016,7 +1016,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { /// Created with the method [`lines_any()`]. /// -/// [`lines_any()`]: ../primitive.str.html#method.lines_any +/// [`lines_any()`]: ../../std/primitive.str.html#method.lines_any #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")] #[derive(Clone)] diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 531be63b7bb..f6b81a5dad3 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -70,6 +70,7 @@ mod rand_impls; // needed by librand; this is necessary because librand doesn't // depend on libstd. This will go away when librand is integrated // into libstd. +#[doc(hidden)] trait FloatMath : Sized { fn exp(self) -> Self; fn ln(self) -> Self; diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 11500286755..5bc5c786160 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -19,7 +19,7 @@ //! [Unicode code point]: http://www.unicode.org/glossary/#code_point //! //! This module exists for technical reasons, the primary documentation for -//! `char` is directly on [the `char` primitive type](../primitive.char.html) +//! `char` is directly on [the `char` primitive type](../../std/primitive.char.html) //! itself. //! //! This module is the home of the iterator implementations for the iterators @@ -46,8 +46,8 @@ pub use tables::UNICODE_VERSION; /// This `struct` is created by the [`to_lowercase()`] method on [`char`]. See /// its documentation for more. /// -/// [`to_lowercase()`]: ../primitive.char.html#method.to_lowercase -/// [`char`]: ../primitive.char.html +/// [`to_lowercase()`]: ../../std/primitive.char.html#method.to_lowercase +/// [`char`]: ../../std/primitive.char.html #[stable(feature = "rust1", since = "1.0.0")] pub struct ToLowercase(CaseMappingIter); @@ -64,8 +64,8 @@ impl Iterator for ToLowercase { /// This `struct` is created by the [`to_uppercase()`] method on [`char`]. See /// its documentation for more. /// -/// [`to_uppercase()`]: ../primitive.char.html#method.to_uppercase -/// [`char`]: ../primitive.char.html +/// [`to_uppercase()`]: ../../std/primitive.char.html#method.to_uppercase +/// [`char`]: ../../std/primitive.char.html #[stable(feature = "rust1", since = "1.0.0")] pub struct ToUppercase(CaseMappingIter); @@ -968,6 +968,6 @@ impl> Iterator for DecodeUtf16 { /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a decoding error. /// It can occur, for example, when giving ill-formed UTF-8 bytes to -/// [`String::from_utf8_lossy`](../string/struct.String.html#method.from_utf8_lossy). +/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). #[unstable(feature = "decode_utf16", reason = "recently added", issue = "27830")] pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 7f57d6dc650..37053025924 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -262,7 +262,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` - /// [floating-point]: ../../../../../reference.html#machine-types + /// [floating-point]: ../reference.html#machine-types #[unstable(feature = "float_extras", reason = "signature is undecided", issue = "27752")] #[inline] diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index a39311f7d10..446e22a20ad 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -206,7 +206,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` - /// [floating-point]: ../../../../../reference.html#machine-types + /// [floating-point]: ../reference.html#machine-types #[unstable(feature = "float_extras", reason = "signature is undecided", issue = "27752")] #[inline] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 24e35b87bf2..65ed879c4ad 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -27,11 +27,11 @@ /// assert!(!bool_val); /// ``` /// -/// [`assert!`]: std/macro.assert!.html -/// [`if` conditionals]: ../../book/if.html -/// [`BitAnd`]: ../ops/trait.BitAnd.html -/// [`BitOr`]: ../ops/trait.BitOr.html -/// [`Not`]: ../ops/trait.Not.html +/// [`assert!`]: macro.assert!.html +/// [`if` conditionals]: ../book/if.html +/// [`BitAnd`]: ops/trait.BitAnd.html +/// [`BitOr`]: ops/trait.BitOr.html +/// [`Not`]: ops/trait.Not.html /// /// # Examples /// @@ -54,7 +54,7 @@ /// } /// ``` /// -/// Also, since `bool` implements the [`Copy`](../marker/trait.Copy.html) trait, we don't +/// Also, since `bool` implements the [`Copy`](marker/trait.Copy.html) trait, we don't /// have to worry about the move semantics (just like the integer and float primitives). mod prim_bool { } @@ -421,7 +421,7 @@ mod prim_str { } /// assert_eq!(tuple.2, 'c'); /// ``` /// -/// For more about tuples, see [the book](../../book/primitive-types.html#tuples). +/// For more about tuples, see [the book](../book/primitive-types.html#tuples). /// /// # Trait implementations /// @@ -437,14 +437,14 @@ mod prim_str { } /// * [`Default`] /// * [`Hash`] /// -/// [`Clone`]: ../clone/trait.Clone.html -/// [`PartialEq`]: ../cmp/trait.PartialEq.html -/// [`Eq`]: ../cmp/trait.Eq.html -/// [`PartialOrd`]: ../cmp/trait.PartialOrd.html -/// [`Ord`]: ../cmp/trait.Ord.html -/// [`Debug`]: ../fmt/trait.Debug.html -/// [`Default`]: ../default/trait.Default.html -/// [`Hash`]: ../hash/trait.Hash.html +/// [`Clone`]: clone/trait.Clone.html +/// [`PartialEq`]: cmp/trait.PartialEq.html +/// [`Eq`]: cmp/trait.Eq.html +/// [`PartialOrd`]: cmp/trait.PartialOrd.html +/// [`Ord`]: cmp/trait.Ord.html +/// [`Debug`]: fmt/trait.Debug.html +/// [`Default`]: default/trait.Default.html +/// [`Hash`]: hash/trait.Hash.html /// /// Due to a temporary restriction in Rust's type system, these traits are only /// implemented on tuples of arity 32 or less. In the future, this may change. -- cgit 1.4.1-3-g733a5 From 8aa268e731aa201e086675f38e4337702c63f104 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Mar 2016 11:19:03 -0800 Subject: std: Fix rustdoc links with std::fmt::Alignment This is actually a reexported implementation detail in the `rt::v1` module but rustdoc doesn't like reexporting items from `doc(hidden)` modules. Do what we'd end up doing anyway from an API perspective and make a public-facing `enum` that can be retranslated under the hood if necessary. --- src/libcore/fmt/mod.rs | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 6cc3b4e01b8..7927b338044 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -22,7 +22,19 @@ use ops::Deref; use result; use slice; use str; -use self::rt::v1::Alignment; + +#[unstable(feature = "fmt_flags_align", issue = "27726")] +/// Possible alignments returned by `Formatter::align` +pub enum Alignment { + /// Indication that contents should be left-aligned. + Left, + /// Indication that contents should be right-aligned. + Right, + /// Indication that contents should be center-aligned. + Center, + /// No alignment was requested. + Unknown, +} #[unstable(feature = "fmt_radix", issue = "27728")] #[rustc_deprecated(since = "1.7.0", reason = "not used enough to stabilize")] @@ -780,7 +792,7 @@ pub fn write(output: &mut Write, args: Arguments) -> Result { width: None, precision: None, buf: output, - align: Alignment::Unknown, + align: rt::v1::Alignment::Unknown, fill: ' ', args: args.args, curarg: args.args.iter(), @@ -920,13 +932,13 @@ impl<'a> Formatter<'a> { Some(min) if self.sign_aware_zero_pad() => { self.fill = '0'; try!(write_prefix(self)); - self.with_padding(min - width, Alignment::Right, |f| { + self.with_padding(min - width, rt::v1::Alignment::Right, |f| { f.buf.write_str(buf) }) } // Otherwise, the sign and prefix goes after the padding Some(min) => { - self.with_padding(min - width, Alignment::Right, |f| { + self.with_padding(min - width, rt::v1::Alignment::Right, |f| { try!(write_prefix(f)); f.buf.write_str(buf) }) } @@ -973,7 +985,8 @@ impl<'a> Formatter<'a> { // If we're under both the maximum and the minimum width, then fill // up the minimum width with the specified string + some alignment. Some(width) => { - self.with_padding(width - s.chars().count(), Alignment::Left, |me| { + let align = rt::v1::Alignment::Left; + self.with_padding(width - s.chars().count(), align, |me| { me.buf.write_str(s) }) } @@ -982,20 +995,21 @@ impl<'a> Formatter<'a> { /// Runs a callback, emitting the correct padding either before or /// afterwards depending on whether right or left alignment is requested. - fn with_padding(&mut self, padding: usize, default: Alignment, + fn with_padding(&mut self, padding: usize, default: rt::v1::Alignment, f: F) -> Result where F: FnOnce(&mut Formatter) -> Result, { use char::CharExt; let align = match self.align { - Alignment::Unknown => default, + rt::v1::Alignment::Unknown => default, _ => self.align }; let (pre_pad, post_pad) = match align { - Alignment::Left => (0, padding), - Alignment::Right | Alignment::Unknown => (padding, 0), - Alignment::Center => (padding / 2, (padding + 1) / 2), + rt::v1::Alignment::Left => (0, padding), + rt::v1::Alignment::Right | + rt::v1::Alignment::Unknown => (padding, 0), + rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2), }; let mut fill = [0; 4]; @@ -1033,7 +1047,7 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = b""; width = if width < sign.len() { 0 } else { width - sign.len() }; - align = Alignment::Right; + align = rt::v1::Alignment::Right; self.fill = '0'; } @@ -1116,7 +1130,14 @@ impl<'a> Formatter<'a> { /// Flag indicating what form of alignment was requested #[unstable(feature = "fmt_flags_align", reason = "method was just created", issue = "27726")] - pub fn align(&self) -> Alignment { self.align } + pub fn align(&self) -> Alignment { + match self.align { + rt::v1::Alignment::Left => Alignment::Left, + rt::v1::Alignment::Right => Alignment::Right, + rt::v1::Alignment::Center => Alignment::Center, + rt::v1::Alignment::Unknown => Alignment::Unknown, + } + } /// Optionally specified integer width that the output should be #[stable(feature = "fmt_flags", since = "1.5.0")] -- cgit 1.4.1-3-g733a5 From e9cb96a56ab6dc883703928825ec7587db74dc1e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Mar 2016 11:20:16 -0800 Subject: rustdoc: Don't inline all impls all at once Right now whenever rustdoc inlines a struct or enum from another crate it ends up inlining *all* `impl` items found in the other crate at the same time. The rationale for this was to discover all trait impls which are otherwise not probed for. This unfortunately picks up a lot of impls of public traits for private types, causing lots of broken links. This commit instead hoards all of those inlined impls into a temporary storage location which is then selectively drawn from whenever we inline a new type. This should ensure that we still inline all relevant impls while avoiding all private ones. --- src/librustdoc/clean/inline.rs | 21 +++++++++++++++++++-- src/librustdoc/clean/mod.rs | 7 +++++++ src/librustdoc/core.rs | 4 ++-- src/librustdoc/test.rs | 4 ++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 32f3706675a..1a281a3a8bb 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -222,7 +222,8 @@ fn build_type(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::ItemEnum { }, false) } -pub fn build_impls(cx: &DocContext, tcx: &TyCtxt, +pub fn build_impls(cx: &DocContext, + tcx: &TyCtxt, did: DefId) -> Vec { tcx.populate_inherent_implementations_for_type_if_necessary(did); let mut impls = Vec::new(); @@ -241,10 +242,12 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt, // Primarily, the impls will be used to populate the documentation for this // type being inlined, but impls can also be used when generating // documentation for primitives (no way to find those specifically). - if cx.populated_crate_impls.borrow_mut().insert(did.krate) { + if !cx.all_crate_impls.borrow_mut().contains_key(&did.krate) { + let mut impls = Vec::new(); for item in tcx.sess.cstore.crate_top_level_items(did.krate) { populate_impls(cx, tcx, item.def, &mut impls); } + cx.all_crate_impls.borrow_mut().insert(did.krate, impls); fn populate_impls(cx: &DocContext, tcx: &TyCtxt, def: cstore::DefLike, @@ -266,6 +269,20 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt, } } + let mut candidates = cx.all_crate_impls.borrow_mut(); + let candidates = candidates.get_mut(&did.krate).unwrap(); + for i in (0..candidates.len()).rev() { + let remove = match candidates[i].inner { + clean::ImplItem(ref i) => { + i.for_.def_id() == Some(did) || i.for_.primitive_type().is_some() + } + _ => continue, + }; + if remove { + impls.push(candidates.swap_remove(i)); + } + } + return impls; } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6c9ee528782..231829a8ed3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1499,6 +1499,13 @@ impl Type { _ => None, } } + + fn def_id(&self) -> Option { + match *self { + ResolvedPath { did, .. } => Some(did), + _ => None, + } + } } impl PrimitiveType { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 345b84e0cac..c889a5f87b0 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -56,7 +56,7 @@ pub struct DocContext<'a, 'tcx: 'a> { pub external_traits: RefCell>>, pub external_typarams: RefCell>>, pub inlined: RefCell>>, - pub populated_crate_impls: RefCell>, + pub all_crate_impls: RefCell>>, pub deref_trait_did: Cell>, } @@ -179,7 +179,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, external_typarams: RefCell::new(Some(HashMap::new())), external_paths: RefCell::new(Some(HashMap::new())), inlined: RefCell::new(Some(HashSet::new())), - populated_crate_impls: RefCell::new(HashSet::new()), + all_crate_impls: RefCell::new(HashMap::new()), deref_trait_did: Cell::new(None), }; debug!("crate: {:?}", ctxt.map.krate()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e97357f9889..8cb3653008a 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -11,7 +11,7 @@ #![allow(deprecated)] use std::cell::{RefCell, Cell}; -use std::collections::{HashSet, HashMap}; +use std::collections::HashMap; use std::dynamic_lib::DynamicLibrary; use std::env; use std::ffi::OsString; @@ -114,7 +114,7 @@ pub fn run(input: &str, external_traits: RefCell::new(None), external_typarams: RefCell::new(None), inlined: RefCell::new(None), - populated_crate_impls: RefCell::new(HashSet::new()), + all_crate_impls: RefCell::new(HashMap::new()), deref_trait_did: Cell::new(None), }; -- cgit 1.4.1-3-g733a5 From 3e6fed3a7a3f783bf967f6c73455743848f31167 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Mar 2016 13:42:32 -0800 Subject: rustbuild: Add the error-index-generator This adds a step and a rule for building the error index as part of rustbuild. --- mk/crates.mk | 2 +- src/bootstrap/build/doc.rs | 13 ++ src/bootstrap/build/mod.rs | 7 + src/bootstrap/build/step.rs | 9 +- src/error_index_generator/main.rs | 203 ---------------------------- src/tools/error_index_generator/Cargo.lock | 4 + src/tools/error_index_generator/Cargo.toml | 8 ++ src/tools/error_index_generator/main.rs | 208 +++++++++++++++++++++++++++++ 8 files changed, 249 insertions(+), 205 deletions(-) delete mode 100644 src/error_index_generator/main.rs create mode 100644 src/tools/error_index_generator/Cargo.lock create mode 100644 src/tools/error_index_generator/Cargo.toml create mode 100644 src/tools/error_index_generator/main.rs diff --git a/mk/crates.mk b/mk/crates.mk index f7fd74e8c9f..4099da59893 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -126,7 +126,7 @@ TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs TOOL_SOURCE_rustc := $(S)src/driver/driver.rs TOOL_SOURCE_rustbook := $(S)src/tools/rustbook/main.rs -TOOL_SOURCE_error_index_generator := $(S)src/error_index_generator/main.rs +TOOL_SOURCE_error_index_generator := $(S)src/tools/error_index_generator/main.rs ONLY_RLIB_core := 1 ONLY_RLIB_libc := 1 diff --git a/src/bootstrap/build/doc.rs b/src/bootstrap/build/doc.rs index ce79a605259..51bf752e06d 100644 --- a/src/bootstrap/build/doc.rs +++ b/src/bootstrap/build/doc.rs @@ -139,3 +139,16 @@ pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) { build.run(&mut cargo); cp_r(&out_dir, out) } + +pub fn error_index(build: &Build, stage: u32, host: &str, out: &Path) { + println!("Documenting stage{} error index ({})", stage, host); + let compiler = Compiler::new(stage, host); + let mut index = Command::new(build.tool(&compiler, "error_index_generator")); + index.arg("html"); + index.arg(out.join("error-index.html")); + + // FIXME: shouldn't have to pass this env var + index.env("CFG_BUILD", &build.config.build); + + build.run(&mut index); +} diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index b4fb67beaf9..058f27c33f6 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -178,6 +178,10 @@ impl Build { ToolRustbook { stage } => { compile::tool(self, stage, target.target, "rustbook"); } + ToolErrorIndex { stage } => { + compile::tool(self, stage, target.target, + "error_index_generator"); + } DocBook { stage } => { doc::rustbook(self, stage, target.target, "book", &doc_out); } @@ -198,6 +202,9 @@ impl Build { DocRustc { stage } => { doc::rustc(self, stage, target.target, &doc_out); } + DocErrorIndex { stage } => { + doc::error_index(self, stage, target.target, &doc_out); + } CheckLinkcheck { stage } => { check::linkcheck(self, stage, target.target); diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs index 7921edcff55..720ba4fd209 100644 --- a/src/bootstrap/build/step.rs +++ b/src/bootstrap/build/step.rs @@ -48,6 +48,7 @@ macro_rules! targets { // Various tools that we can build as part of the build. (tool_linkchecker, ToolLinkchecker { stage: u32 }), (tool_rustbook, ToolRustbook { stage: u32 }), + (tool_error_index, ToolErrorIndex { stage: u32 }), // Steps for long-running native builds. Ideally these wouldn't // actually exist and would be part of build scripts, but for now @@ -68,6 +69,7 @@ macro_rules! targets { (doc_standalone, DocStandalone { stage: u32 }), (doc_std, DocStd { stage: u32 }), (doc_rustc, DocRustc { stage: u32 }), + (doc_error_index, DocErrorIndex { stage: u32 }), // Steps for running tests. The 'check' target is just a pseudo // target to depend on a bunch of others. @@ -265,6 +267,9 @@ impl<'a> Step<'a> { Source::DocStyle { stage } => { vec![self.tool_rustbook(stage)] } + Source::DocErrorIndex { stage } => { + vec![self.tool_error_index(stage)] + } Source::DocStandalone { stage } => { vec![self.rustc(stage)] } @@ -274,7 +279,8 @@ impl<'a> Step<'a> { Source::Doc { stage } => { vec![self.doc_book(stage), self.doc_nomicon(stage), self.doc_style(stage), self.doc_standalone(stage), - self.doc_std(stage)] + self.doc_std(stage), + self.doc_error_index(stage)] } Source::Check { stage, compiler: _ } => { vec![self.check_linkcheck(stage)] @@ -286,6 +292,7 @@ impl<'a> Step<'a> { Source::ToolLinkchecker { stage } => { vec![self.libstd(stage, self.compiler(stage))] } + Source::ToolErrorIndex { stage } | Source::ToolRustbook { stage } => { vec![self.librustc(stage, self.compiler(stage))] } diff --git a/src/error_index_generator/main.rs b/src/error_index_generator/main.rs deleted file mode 100644 index db9dd006f3c..00000000000 --- a/src/error_index_generator/main.rs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private, rustdoc)] - -extern crate syntax; -extern crate rustdoc; -extern crate serialize as rustc_serialize; - -use std::collections::BTreeMap; -use std::fs::{read_dir, File}; -use std::io::{Read, Write}; -use std::env; -use std::path::Path; -use std::error::Error; - -use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; - -use rustdoc::html::markdown::Markdown; -use rustc_serialize::json; - -enum OutputFormat { - HTML(HTMLFormatter), - Markdown(MarkdownFormatter), - Unknown(String), -} - -impl OutputFormat { - fn from(format: &str) -> OutputFormat { - match &*format.to_lowercase() { - "html" => OutputFormat::HTML(HTMLFormatter), - "markdown" => OutputFormat::Markdown(MarkdownFormatter), - s => OutputFormat::Unknown(s.to_owned()), - } - } -} - -trait Formatter { - fn header(&self, output: &mut Write) -> Result<(), Box>; - fn title(&self, output: &mut Write) -> Result<(), Box>; - fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata, - err_code: &str) -> Result<(), Box>; - fn footer(&self, output: &mut Write) -> Result<(), Box>; -} - -struct HTMLFormatter; -struct MarkdownFormatter; - -impl Formatter for HTMLFormatter { - fn header(&self, output: &mut Write) -> Result<(), Box> { - try!(write!(output, r##" - - -Rust Compiler Error Index - - - - - - - -"##)); - Ok(()) - } - - fn title(&self, output: &mut Write) -> Result<(), Box> { - try!(write!(output, "

    Rust Compiler Error Index

    \n")); - Ok(()) - } - - fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata, - err_code: &str) -> Result<(), Box> { - // Enclose each error in a div so they can be shown/hidden en masse. - let desc_desc = match info.description { - Some(_) => "error-described", - None => "error-undescribed", - }; - let use_desc = match info.use_site { - Some(_) => "error-used", - None => "error-unused", - }; - try!(write!(output, "
    ", desc_desc, use_desc)); - - // Error title (with self-link). - try!(write!(output, - "

    {0}

    \n", - err_code)); - - // Description rendered as markdown. - match info.description { - Some(ref desc) => try!(write!(output, "{}", Markdown(desc))), - None => try!(write!(output, "

    No description.

    \n")), - } - - try!(write!(output, "
    \n")); - Ok(()) - } - - fn footer(&self, output: &mut Write) -> Result<(), Box> { - try!(write!(output, "\n")); - Ok(()) - } -} - -impl Formatter for MarkdownFormatter { - #[allow(unused_variables)] - fn header(&self, output: &mut Write) -> Result<(), Box> { - Ok(()) - } - - fn title(&self, output: &mut Write) -> Result<(), Box> { - try!(write!(output, "# Rust Compiler Error Index\n")); - Ok(()) - } - - fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata, - err_code: &str) -> Result<(), Box> { - Ok(match info.description { - Some(ref desc) => try!(write!(output, "## {}\n{}\n", err_code, desc)), - None => (), - }) - } - - #[allow(unused_variables)] - fn footer(&self, output: &mut Write) -> Result<(), Box> { - Ok(()) - } -} - -/// Load all the metadata files from `metadata_dir` into an in-memory map. -fn load_all_errors(metadata_dir: &Path) -> Result> { - let mut all_errors = BTreeMap::new(); - - for entry in try!(read_dir(metadata_dir)) { - let path = try!(entry).path(); - - let mut metadata_str = String::new(); - try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str))); - - let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str)); - - for (err_code, info) in some_errors { - all_errors.insert(err_code, info); - } - } - - Ok(all_errors) -} - -/// Output an HTML page for the errors in `err_map` to `output_path`. -fn render_error_page(err_map: &ErrorMetadataMap, output_path: &Path, - formatter: T) -> Result<(), Box> { - let mut output_file = try!(File::create(output_path)); - - try!(formatter.header(&mut output_file)); - try!(formatter.title(&mut output_file)); - - for (err_code, info) in err_map { - try!(formatter.error_code_block(&mut output_file, info, err_code)); - } - - formatter.footer(&mut output_file) -} - -fn main_with_result(format: OutputFormat) -> Result<(), Box> { - let build_arch = try!(env::var("CFG_BUILD")); - let metadata_dir = get_metadata_dir(&build_arch); - let err_map = try!(load_all_errors(&metadata_dir)); - match format { - OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s), - OutputFormat::HTML(h) => try!(render_error_page(&err_map, - Path::new("doc/error-index.html"), - h)), - OutputFormat::Markdown(m) => try!(render_error_page(&err_map, - Path::new("doc/error-index.md"), - m)), - } - Ok(()) -} - -fn parse_args() -> OutputFormat { - for arg in env::args().skip(1) { - return OutputFormat::from(&arg); - } - OutputFormat::from("html") -} - -fn main() { - if let Err(e) = main_with_result(parse_args()) { - panic!("{}", e.description()); - } -} diff --git a/src/tools/error_index_generator/Cargo.lock b/src/tools/error_index_generator/Cargo.lock new file mode 100644 index 00000000000..b7d2cfcaaa1 --- /dev/null +++ b/src/tools/error_index_generator/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "error_index_generator" +version = "0.0.0" + diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml new file mode 100644 index 00000000000..5c5ca273e9c --- /dev/null +++ b/src/tools/error_index_generator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +authors = ["The Rust Project Developers"] +name = "error_index_generator" +version = "0.0.0" + +[[bin]] +name = "error_index_generator" +path = "main.rs" diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs new file mode 100644 index 00000000000..4343aef00a9 --- /dev/null +++ b/src/tools/error_index_generator/main.rs @@ -0,0 +1,208 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_private, rustdoc)] + +extern crate syntax; +extern crate rustdoc; +extern crate serialize as rustc_serialize; + +use std::collections::BTreeMap; +use std::env; +use std::error::Error; +use std::fs::{read_dir, File}; +use std::io::{Read, Write}; +use std::path::Path; +use std::path::PathBuf; + +use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; + +use rustdoc::html::markdown::Markdown; +use rustc_serialize::json; + +enum OutputFormat { + HTML(HTMLFormatter), + Markdown(MarkdownFormatter), + Unknown(String), +} + +impl OutputFormat { + fn from(format: &str) -> OutputFormat { + match &*format.to_lowercase() { + "html" => OutputFormat::HTML(HTMLFormatter), + "markdown" => OutputFormat::Markdown(MarkdownFormatter), + s => OutputFormat::Unknown(s.to_owned()), + } + } +} + +trait Formatter { + fn header(&self, output: &mut Write) -> Result<(), Box>; + fn title(&self, output: &mut Write) -> Result<(), Box>; + fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata, + err_code: &str) -> Result<(), Box>; + fn footer(&self, output: &mut Write) -> Result<(), Box>; +} + +struct HTMLFormatter; +struct MarkdownFormatter; + +impl Formatter for HTMLFormatter { + fn header(&self, output: &mut Write) -> Result<(), Box> { + try!(write!(output, r##" + + +Rust Compiler Error Index + + + + + + + +"##)); + Ok(()) + } + + fn title(&self, output: &mut Write) -> Result<(), Box> { + try!(write!(output, "

    Rust Compiler Error Index

    \n")); + Ok(()) + } + + fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata, + err_code: &str) -> Result<(), Box> { + // Enclose each error in a div so they can be shown/hidden en masse. + let desc_desc = match info.description { + Some(_) => "error-described", + None => "error-undescribed", + }; + let use_desc = match info.use_site { + Some(_) => "error-used", + None => "error-unused", + }; + try!(write!(output, "
    ", desc_desc, use_desc)); + + // Error title (with self-link). + try!(write!(output, + "

    {0}

    \n", + err_code)); + + // Description rendered as markdown. + match info.description { + Some(ref desc) => try!(write!(output, "{}", Markdown(desc))), + None => try!(write!(output, "

    No description.

    \n")), + } + + try!(write!(output, "
    \n")); + Ok(()) + } + + fn footer(&self, output: &mut Write) -> Result<(), Box> { + try!(write!(output, "\n")); + Ok(()) + } +} + +impl Formatter for MarkdownFormatter { + #[allow(unused_variables)] + fn header(&self, output: &mut Write) -> Result<(), Box> { + Ok(()) + } + + fn title(&self, output: &mut Write) -> Result<(), Box> { + try!(write!(output, "# Rust Compiler Error Index\n")); + Ok(()) + } + + fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata, + err_code: &str) -> Result<(), Box> { + Ok(match info.description { + Some(ref desc) => try!(write!(output, "## {}\n{}\n", err_code, desc)), + None => (), + }) + } + + #[allow(unused_variables)] + fn footer(&self, output: &mut Write) -> Result<(), Box> { + Ok(()) + } +} + +/// Load all the metadata files from `metadata_dir` into an in-memory map. +fn load_all_errors(metadata_dir: &Path) -> Result> { + let mut all_errors = BTreeMap::new(); + + for entry in try!(read_dir(metadata_dir)) { + let path = try!(entry).path(); + + let mut metadata_str = String::new(); + try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str))); + + let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str)); + + for (err_code, info) in some_errors { + all_errors.insert(err_code, info); + } + } + + Ok(all_errors) +} + +/// Output an HTML page for the errors in `err_map` to `output_path`. +fn render_error_page(err_map: &ErrorMetadataMap, output_path: &Path, + formatter: T) -> Result<(), Box> { + let mut output_file = try!(File::create(output_path)); + + try!(formatter.header(&mut output_file)); + try!(formatter.title(&mut output_file)); + + for (err_code, info) in err_map { + try!(formatter.error_code_block(&mut output_file, info, err_code)); + } + + formatter.footer(&mut output_file) +} + +fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box> { + let build_arch = try!(env::var("CFG_BUILD")); + let metadata_dir = get_metadata_dir(&build_arch); + let err_map = try!(load_all_errors(&metadata_dir)); + match format { + OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s), + OutputFormat::HTML(h) => try!(render_error_page(&err_map, dst, h)), + OutputFormat::Markdown(m) => try!(render_error_page(&err_map, dst, m)), + } + Ok(()) +} + +fn parse_args() -> (OutputFormat, PathBuf) { + let mut args = env::args().skip(1); + let format = args.next().map(|a| OutputFormat::from(&a)) + .unwrap_or(OutputFormat::from("html")); + let dst = args.next().map(PathBuf::from).unwrap_or_else(|| { + match format { + OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"), + OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"), + OutputFormat::Unknown(..) => PathBuf::from(""), + } + }); + (format, dst) +} + +fn main() { + let (format, dst) = parse_args(); + if let Err(e) = main_with_result(format, &dst) { + panic!("{}", e.description()); + } +} -- cgit 1.4.1-3-g733a5