about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMark Simulacrum <mark.simulacrum@gmail.com>2017-07-18 18:03:38 -0600
committerMark Simulacrum <mark.simulacrum@gmail.com>2017-07-20 11:24:37 -0600
commit56128fb3acdbb40876d1fc8aee613792ebef3080 (patch)
treec8753059843a319610a541faa01b990a0aac6e0f /src
parentbca1e2ffd1658e800e15e730dee5d6cc02722270 (diff)
downloadrust-56128fb3acdbb40876d1fc8aee613792ebef3080.tar.gz
rust-56128fb3acdbb40876d1fc8aee613792ebef3080.zip
Implement available paths list.
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/builder.rs105
-rw-r--r--src/bootstrap/check.rs66
-rw-r--r--src/bootstrap/compile.rs47
-rw-r--r--src/bootstrap/dist.rs50
-rw-r--r--src/bootstrap/doc.rs58
-rw-r--r--src/bootstrap/flags.rs8
-rw-r--r--src/bootstrap/install.rs6
-rw-r--r--src/bootstrap/native.rs14
-rw-r--r--src/bootstrap/tool.rs26
9 files changed, 224 insertions, 156 deletions
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 77f8dda251b..8613bc7a7ba 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -16,6 +16,7 @@ use std::process::Command;
 use std::fs;
 use std::ops::Deref;
 use std::any::Any;
+use std::collections::BTreeSet;
 
 use compile;
 use install;
@@ -70,7 +71,7 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
     /// will execute. However, it does not get called in a "default" context
     /// when we are not passed any paths; in that case, make_run is called
     /// directly.
-    fn should_run(builder: &Builder, path: &Path) -> bool;
+    fn should_run(run: ShouldRun) -> ShouldRun;
 
     /// Build up a "root" rule, either as a default rule or from a path passed
     /// to us.
@@ -92,6 +93,43 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
     }
 }
 
+#[derive(Clone)]
+pub struct ShouldRun<'a> {
+    builder: &'a Builder<'a>,
+    // use a BTreeSet to maintain sort order
+    paths: BTreeSet<PathBuf>,
+}
+
+impl<'a> ShouldRun<'a> {
+    fn new(builder: &'a Builder) -> ShouldRun<'a> {
+        ShouldRun {
+            builder: builder,
+            paths: BTreeSet::new(),
+        }
+    }
+
+    pub fn krate(mut self, name: &str) -> Self {
+        for (_, krate_path) in self.builder.crates(name) {
+            self.paths.insert(PathBuf::from(krate_path));
+        }
+        self
+    }
+
+    pub fn path(mut self, path: &str) -> Self {
+        self.paths.insert(PathBuf::from(path));
+        self
+    }
+
+    // allows being more explicit about why should_run in Step returns the value passed to it
+    pub fn never(self) -> ShouldRun<'a> {
+        self
+    }
+
+    fn run(&self, path: &Path) -> bool {
+        self.paths.iter().any(|p| path.ends_with(p))
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum Kind {
     Build,
@@ -115,7 +153,7 @@ macro_rules! check {
             for path in paths {
                 let mut attempted_run = false;
                 $({
-                    if <$rule>::should_run($self, path) {
+                    if <$rule>::should_run(ShouldRun::new($self)).run(path) {
                         attempted_run = true;
                         $self.maybe_run::<$rule>(Some(path));
                     }
@@ -129,6 +167,60 @@ macro_rules! check {
 }
 
 impl<'a> Builder<'a> {
+    pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
+        let kind = match subcommand {
+            "build" => Kind::Build,
+            "doc" => Kind::Doc,
+            "test" => Kind::Test,
+            "bench" => Kind::Bench,
+            "dist" => Kind::Dist,
+            "install" => Kind::Install,
+            _ => return None,
+        };
+
+        let builder = Builder {
+            build: build,
+            top_stage: build.flags.stage.unwrap_or(2),
+            kind: kind,
+            cache: Cache::new(),
+            stack: RefCell::new(Vec::new()),
+        };
+
+        let builder = &builder;
+        let mut should_run = ShouldRun::new(builder);
+        macro_rules! into_shouldrun {
+            ($should_run:ident, $($rule:ty),+ $(,)*) => {{
+                $(
+                    $should_run = <$rule>::should_run($should_run);
+                )+
+            }};
+        }
+        match builder.kind {
+            Kind::Build => into_shouldrun!(should_run, compile::Std, compile::Test, compile::Rustc,
+                compile::StartupObjects, tool::BuildManifest, tool::Rustbook, tool::ErrorIndex,
+                tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest,
+                tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
+                tool::RustInstaller, tool::Cargo, tool::Rls),
+            Kind::Test => into_shouldrun!(should_run, check::Tidy, check::Bootstrap,
+                check::Compiletest, check::Crate, check::CrateLibrustc, check::Linkcheck,
+                check::Cargotest, check::Cargo, check::Docs, check::ErrorIndex, check::Distcheck),
+            Kind::Bench => into_shouldrun!(should_run, check::Crate, check::CrateLibrustc),
+            Kind::Doc => into_shouldrun!(should_run, doc::UnstableBook, doc::UnstableBookGen,
+                doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex,
+                doc::Nomicon, doc::Reference),
+            Kind::Dist => into_shouldrun!(should_run, dist::Docs, dist::Mingw, dist::Rustc,
+                dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src,
+                dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Extended, dist::HashSign),
+            Kind::Install => into_shouldrun!(should_run, install::Docs, install::Std,
+                install::Cargo, install::Rls, install::Analysis, install::Src, install::Rustc),
+        }
+        let mut help = String::from("Available paths:\n");
+        for path in should_run.paths {
+            help.push_str(format!("    ./x.py {} {}\n", subcommand, path.display()).as_str());
+        }
+        Some(help)
+    }
+
     pub fn run(build: &Build) {
         let (kind, paths) = match build.flags.cmd {
             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
@@ -170,9 +262,8 @@ impl<'a> Builder<'a> {
 
     pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
         let paths = paths.unwrap_or(&[]);
-        check!(self, paths, doc::UnstableBook, doc::UnstableBookGen, doc::Rustbook, doc::TheBook,
-            doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex,
-            doc::Nomicon, doc::Reference);
+        check!(self, paths, doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone,
+            doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, doc::Reference);
     }
 
     /// Obtain a compiler at a given stage and for a given host. Explictly does
@@ -200,8 +291,8 @@ impl<'a> Builder<'a> {
         impl Step for Libdir {
             type Output = Interned<PathBuf>;
 
-            fn should_run(_builder: &Builder, _path: &Path) -> bool {
-                false
+            fn should_run(run: ShouldRun) -> ShouldRun {
+                run.never()
             }
 
             fn run(self, builder: &Builder) -> Interned<PathBuf> {
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 6c41a76e70f..847307959cb 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -31,7 +31,7 @@ use util::{self, dylib_path, dylib_path_var};
 
 use compile;
 use native;
-use builder::{Kind, Builder, Compiler, Step};
+use builder::{Kind, ShouldRun, Builder, Compiler, Step};
 use tool::{self, Tool};
 use cache::{INTERNER, Interned};
 
@@ -121,8 +121,8 @@ impl Step for Linkcheck {
                             .arg(build.out.join(host).join("doc")));
     }
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/linkchecker")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/linkchecker")
     }
 
     fn make_run(
@@ -157,8 +157,8 @@ impl Step for Cargotest {
     type Output = ();
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/cargotest")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/cargotest")
     }
 
     fn make_run(
@@ -212,8 +212,8 @@ impl Step for Cargo {
     type Output = ();
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/cargo")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/cargo")
     }
 
     fn make_run(
@@ -264,8 +264,8 @@ impl Step for Rls {
     type Output = ();
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/rls")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/rls")
     }
 
     fn make_run(
@@ -348,8 +348,8 @@ impl Step for Tidy {
         try_run(build, &mut cmd);
     }
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/tidy")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/tidy")
     }
 
     fn make_run(
@@ -531,13 +531,14 @@ impl Step for Compiletest {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
+    fn should_run(mut run: ShouldRun) -> ShouldRun {
         // Note that this is general, while a few more cases are skipped inside
         // run() itself. This is to avoid duplication across should_run and
         // make_run.
-        COMPILETESTS.iter().chain(DEFAULT_COMPILETESTS).chain(HOST_COMPILETESTS).any(|&test| {
-            path.ends_with(test.path)
-        })
+        for test in COMPILETESTS.iter().chain(DEFAULT_COMPILETESTS).chain(HOST_COMPILETESTS) {
+            run = run.path(test.path);
+        }
+        run
     }
 
     fn make_run(
@@ -803,8 +804,8 @@ impl Step for Docs {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/doc")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/doc")
     }
 
     fn make_run(
@@ -873,8 +874,8 @@ impl Step for ErrorIndex {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/error_index_generator")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/error_index_generator")
     }
 
     fn make_run(
@@ -973,10 +974,8 @@ impl Step for CrateLibrustc {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        builder.crates("rustc-main").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.krate("rustc-main")
     }
 
     fn make_run(
@@ -1087,13 +1086,8 @@ impl Step for Crate {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        builder.crates("std").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        }) ||
-        builder.crates("test").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.krate("std").krate("test")
     }
 
     fn make_run(
@@ -1358,8 +1352,8 @@ pub struct RemoteCopyLibs {
 impl Step for RemoteCopyLibs {
     type Output = ();
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     fn run(self, builder: &Builder) {
@@ -1413,8 +1407,8 @@ pub struct Distcheck;
 impl Step for Distcheck {
     type Output = ();
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("distcheck")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("distcheck")
     }
 
     /// Run "distcheck", a 'make check' from a tarball
@@ -1503,8 +1497,8 @@ impl Step for Bootstrap {
         try_run(build, &mut cmd);
     }
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/bootstrap")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/bootstrap")
     }
 
     fn make_run(
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index eccecc983f1..134d957220d 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -34,7 +34,7 @@ use {Build, Compiler, Mode};
 use native;
 
 use cache::{INTERNER, Interned};
-use builder::{Step, Builder};
+use builder::{Step, ShouldRun, Builder};
 
 //
 //    // Crates which have build scripts need to rely on this rule to ensure that
@@ -152,11 +152,8 @@ impl Step for Std {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/libstd") ||
-        builder.crates("std").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/libstd").krate("std")
     }
 
     fn make_run(
@@ -277,8 +274,8 @@ struct StdLink {
 impl Step for StdLink {
     type Output = ();
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Link all libstd rlibs/dylibs into the sysroot location.
@@ -350,8 +347,8 @@ pub struct StartupObjects {
 impl Step for StartupObjects {
     type Output = ();
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/rtstartup")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/rtstartup")
     }
 
     fn make_run(
@@ -422,11 +419,8 @@ impl Step for Test {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/libtest") ||
-        builder.crates("test").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/libtest").krate("test")
     }
 
     fn make_run(
@@ -508,8 +502,8 @@ pub struct TestLink {
 impl Step for TestLink {
     type Output = ();
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Same as `std_link`, only for libtest
@@ -548,11 +542,8 @@ impl Step for Rustc {
     const ONLY_HOSTS: bool = true;
     const DEFAULT: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/librustc") ||
-        builder.crates("rustc-main").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/librustc").krate("rustc-main")
     }
 
     fn make_run(
@@ -700,8 +691,8 @@ struct RustcLink {
 impl Step for RustcLink {
     type Output = ();
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Same as `std_link`, only for librustc
@@ -756,8 +747,8 @@ pub struct Sysroot {
 impl Step for Sysroot {
     type Output = Interned<PathBuf>;
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Returns the sysroot for the `compiler` specified that *this build system
@@ -806,8 +797,8 @@ pub struct Assemble {
 impl Step for Assemble {
     type Output = Compiler;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/rustc")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/rustc")
     }
 
     /// Prepare a new compiler from the artifacts in `stage`
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index e9a2fc7fc1a..e3d6c74ec22 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -37,7 +37,7 @@ use build_helper::output;
 use {Build, Compiler, Mode};
 use channel;
 use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe};
-use builder::{Builder, Step};
+use builder::{Builder, ShouldRun, Step};
 use compile;
 use tool::{self, Tool};
 use cache::{INTERNER, Interned};
@@ -83,8 +83,8 @@ impl Step for Docs {
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/doc")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/doc")
     }
 
     fn make_run(
@@ -296,8 +296,8 @@ impl Step for Mingw {
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     fn make_run(
@@ -367,8 +367,8 @@ impl Step for Rustc {
     const ONLY_HOSTS: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/librustc")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/librustc")
     }
 
     fn make_run(
@@ -508,8 +508,8 @@ pub struct DebuggerScripts {
 impl Step for DebuggerScripts {
     type Output = ();
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/etc/lldb_batchmode.py")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/lldb_batchmode.py")
     }
 
     fn make_run(
@@ -584,8 +584,8 @@ impl Step for Std {
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/libstd")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/libstd")
     }
 
     fn make_run(
@@ -666,8 +666,8 @@ impl Step for Analysis {
     const DEFAULT: bool = true;
     const ONLY_BUILD_TARGETS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("analysis")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("analysis")
     }
 
     fn make_run(
@@ -794,8 +794,8 @@ impl Step for Src {
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_BUILD: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src")
     }
 
     fn make_run(
@@ -893,8 +893,8 @@ impl Step for PlainSourceTarball {
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_BUILD: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src")
     }
 
     fn make_run(
@@ -1046,8 +1046,8 @@ impl Step for Cargo {
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("cargo")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("cargo")
     }
 
     fn make_run(
@@ -1144,8 +1144,8 @@ impl Step for Rls {
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("rls")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("rls")
     }
 
     fn make_run(
@@ -1240,8 +1240,8 @@ impl Step for Extended {
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("cargo")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("cargo")
     }
 
     fn make_run(
@@ -1648,8 +1648,8 @@ impl Step for HashSign {
     const ONLY_HOSTS: bool = true;
     const ONLY_BUILD: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("hash-and-sign")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("hash-and-sign")
     }
 
     fn make_run(
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 65110dbaae9..1fd39ba878f 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -27,7 +27,7 @@ use Mode;
 use build_helper::up_to_date;
 
 use util::{cp_r, symlink_dir};
-use builder::{Builder, Step};
+use builder::{Builder, ShouldRun, Step};
 use tool::Tool;
 use compile;
 use cache::{INTERNER, Interned};
@@ -44,8 +44,8 @@ macro_rules! book {
             type Output = ();
             const DEFAULT: bool = true;
 
-            fn should_run(_builder: &Builder, path: &Path) -> bool {
-                path.ends_with($path)
+            fn should_run(run: ShouldRun) -> ShouldRun {
+                run.path($path)
             }
 
             fn make_run(
@@ -99,7 +99,7 @@ book!(
 );
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct Rustbook {
+struct Rustbook {
     target: Interned<String>,
     name: Interned<String>,
 }
@@ -109,8 +109,8 @@ impl Step for Rustbook {
 
     // rustbook is never directly called, and only serves as a shim for the nomicon and the
     // reference.
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Invoke `rustbook` for `target` for the doc book `name`.
@@ -149,8 +149,8 @@ impl Step for UnstableBook {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/doc/unstable-book")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/doc/unstable-book")
     }
 
     fn make_run(
@@ -179,7 +179,7 @@ impl Step for UnstableBook {
 }
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct RustbookSrc {
+struct RustbookSrc {
     target: Interned<String>,
     name: Interned<String>,
     src: Interned<PathBuf>,
@@ -188,9 +188,8 @@ pub struct RustbookSrc {
 impl Step for RustbookSrc {
     type Output = ();
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        // RustbookSrc is also never run directly, only as a helper to other rules
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path.
@@ -242,8 +241,8 @@ impl Step for TheBook {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/doc/book")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/doc/book")
     }
 
     fn make_run(
@@ -366,8 +365,8 @@ impl Step for Standalone {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/doc")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/doc")
     }
 
     fn make_run(
@@ -475,12 +474,11 @@ impl Step for Std {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        builder.crates("std").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.krate("std")
     }
 
+
     fn make_run(
         builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
     ) {
@@ -588,10 +586,8 @@ impl Step for Test {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        builder.crates("test").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.krate("test")
     }
 
     fn make_run(
@@ -678,10 +674,8 @@ impl Step for Rustc {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(builder: &Builder, path: &Path) -> bool {
-        builder.crates("rustc-main").into_iter().any(|(_, krate_path)| {
-            path.ends_with(krate_path)
-        })
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.krate("rustc-main")
     }
 
     fn make_run(
@@ -780,8 +774,8 @@ impl Step for ErrorIndex {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/error_index_generator")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/error_index_generator")
     }
 
     fn make_run(
@@ -844,8 +838,8 @@ impl Step for UnstableBookGen {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/doc/unstable-book")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/unstable-book-gen")
     }
 
     fn make_run(
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index b1ea441795e..1a3a008ed26 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -23,6 +23,7 @@ use getopts::Options;
 use Build;
 use config::Config;
 use metadata;
+use builder::Builder;
 
 use cache::{Interned, INTERNER};
 
@@ -248,11 +249,8 @@ Arguments:
             let mut build = Build::new(flags, config);
             metadata::build(&mut build);
 
-            // FIXME: How should this happen now? Not super clear...
-            // let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
-            // if maybe_rules_help.is_some() {
-            //     extra_help.push_str(maybe_rules_help.unwrap().as_str());
-            // }
+            let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
+            extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
         } else {
             extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
                      subcommand).as_str());
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 6b6160f43ca..fac69f89dc1 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -20,7 +20,7 @@ use std::process::Command;
 
 use dist::{self, pkgname, sanitize_sh, tmpdir};
 
-use builder::{Builder, Step};
+use builder::{Builder, ShouldRun, Step};
 use cache::Interned;
 
 pub fn install_docs(builder: &Builder, stage: u32, host: Interned<String>) {
@@ -149,8 +149,8 @@ macro_rules! install {
             const ONLY_HOSTS: bool = $only_hosts;
             $(const $c: bool = true;)*
 
-            fn should_run(_builder: &Builder, path: &Path) -> bool {
-                path.ends_with($path)
+            fn should_run(run: ShouldRun) -> ShouldRun {
+                run.path($path)
             }
 
             fn make_run(
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index b60a3760eb2..af13d866497 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -32,7 +32,7 @@ use gcc;
 use Build;
 use util;
 use build_helper::up_to_date;
-use builder::{Builder, Step};
+use builder::{Builder, ShouldRun, Step};
 use cache::Interned;
 
 // rules.build("llvm", "src/llvm")
@@ -55,8 +55,8 @@ impl Step for Llvm {
     type Output = ();
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/llvm")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/llvm")
     }
 
     /// Compile LLVM for `target`.
@@ -257,8 +257,8 @@ pub struct TestHelpers {
 impl Step for TestHelpers {
     type Output = ();
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/rt/rust_test_helpers.c")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/rt/rust_test_helpers.c")
     }
 
     fn make_run(
@@ -322,8 +322,8 @@ pub struct Openssl {
 impl Step for Openssl {
     type Output = ();
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     fn run(self, builder: &Builder) {
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 9c5592cd61b..9554eb3e2a5 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -14,7 +14,7 @@ use std::process::Command;
 
 use Mode;
 use Compiler;
-use builder::{Step, Builder};
+use builder::{Step, ShouldRun, Builder};
 use util::{exe, add_lib_path};
 use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp, Rustc};
 use native;
@@ -55,8 +55,8 @@ pub struct CleanTools {
 impl Step for CleanTools {
     type Output = ();
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Build a tool in `src/tools`
@@ -93,8 +93,8 @@ pub struct ToolBuild {
 impl Step for ToolBuild {
     type Output = PathBuf;
 
-    fn should_run(_builder: &Builder, _path: &Path) -> bool {
-        false
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.never()
     }
 
     /// Build a tool in `src/tools`
@@ -183,8 +183,8 @@ macro_rules! tool {
         impl Step for $name {
             type Output = PathBuf;
 
-            fn should_run(_builder: &Builder, path: &Path) -> bool {
-                path.ends_with($path)
+            fn should_run(run: ShouldRun) -> ShouldRun {
+                run.path($path)
             }
 
             fn make_run(
@@ -274,8 +274,8 @@ pub struct RemoteTestServer {
 impl Step for RemoteTestServer {
     type Output = PathBuf;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/remote-test-server")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/remote-test-server")
     }
 
     fn make_run(
@@ -325,8 +325,8 @@ impl Step for Cargo {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/cargo")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/cargo")
     }
 
     fn make_run(
@@ -384,8 +384,8 @@ impl Step for Rls {
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
-    fn should_run(_builder: &Builder, path: &Path) -> bool {
-        path.ends_with("src/tools/rls")
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/rls")
     }
 
     fn make_run(