Allow iterating over step descriptions.

This simplifies code and allows working mostly with normal Rust instead
of macros.
This commit is contained in:
Mark Simulacrum 2017-07-19 06:55:46 -06:00
parent 56128fb3ac
commit 5bdec80fe3

View File

@ -93,6 +93,89 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
}
}
struct StepDescription {
default: bool,
only_hosts: bool,
only_build_targets: bool,
only_build: bool,
should_run: fn(ShouldRun) -> ShouldRun,
make_run: fn(&Builder, Option<&Path>, Interned<String>, Interned<String>),
}
impl StepDescription {
fn from<S: Step>() -> StepDescription {
StepDescription {
default: S::DEFAULT,
only_hosts: S::ONLY_HOSTS,
only_build_targets: S::ONLY_BUILD_TARGETS,
only_build: S::ONLY_BUILD,
should_run: S::should_run,
make_run: S::make_run,
}
}
fn maybe_run(&self, builder: &Builder, path: Option<&Path>) {
let build = builder.build;
let hosts = if self.only_build_targets || self.only_build {
&build.config.host[..1]
} else {
&build.hosts
};
// Determine the actual targets participating in this rule.
// NOTE: We should keep the full projection from build triple to
// the hosts for the dist steps, now that the hosts array above is
// truncated to avoid duplication of work in that case. Therefore
// the original non-shadowed hosts array is used below.
let targets = if self.only_hosts {
// If --target was specified but --host wasn't specified,
// don't run any host-only tests. Also, respect any `--host`
// overrides as done for `hosts`.
if build.flags.host.len() > 0 {
&build.flags.host[..]
} else if build.flags.target.len() > 0 {
&[]
} else if self.only_build {
&build.config.host[..1]
} else {
&build.config.host[..]
}
} else {
&build.targets
};
for host in hosts {
for target in targets {
(self.make_run)(builder, path, *host, *target);
}
}
}
fn run(v: &[StepDescription], builder: &Builder, paths: &[PathBuf]) {
if paths.is_empty() {
for desc in v {
if desc.default {
desc.maybe_run(builder, None);
}
}
} else {
for path in paths {
let mut attempted_run = false;
for desc in v {
if (desc.should_run)(ShouldRun::new(builder)).run(path) {
attempted_run = true;
desc.maybe_run(builder, Some(path));
}
}
if !attempted_run {
eprintln!("Warning: no rules matched {}.", path.display());
}
}
}
}
}
#[derive(Clone)]
pub struct ShouldRun<'a> {
builder: &'a Builder<'a>,
@ -140,33 +223,34 @@ pub enum Kind {
Install,
}
macro_rules! check {
($self:ident, $paths:ident, $($rule:ty),+ $(,)*) => {{
let paths = $paths;
if paths.is_empty() {
$({
if <$rule>::DEFAULT {
$self.maybe_run::<$rule>(None);
}
})+
} else {
for path in paths {
let mut attempted_run = false;
$({
if <$rule>::should_run(ShouldRun::new($self)).run(path) {
attempted_run = true;
$self.maybe_run::<$rule>(Some(path));
}
})+
if !attempted_run {
eprintln!("Warning: no rules matched {}.", path.display());
}
}
}
}};
}
impl<'a> Builder<'a> {
fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
macro_rules! describe {
($($rule:ty),+ $(,)*) => {{
vec![$(StepDescription::from::<$rule>()),+]
}};
}
match kind {
Kind::Build => describe!(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 => describe!(check::Tidy, check::Bootstrap, check::Compiletest, check::Crate,
check::CrateLibrustc, check::Linkcheck, check::Cargotest, check::Cargo, check::Docs,
check::ErrorIndex, check::Distcheck),
Kind::Bench => describe!(check::Crate, check::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
doc::Reference),
Kind::Dist => describe!(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 => describe!(install::Docs, install::Std, install::Cargo, install::Rls,
install::Analysis, install::Src, install::Rustc),
}
}
pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
let kind = match subcommand {
"build" => Kind::Build,
@ -188,31 +272,8 @@ impl<'a> Builder<'a> {
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),
for desc in Builder::get_step_descriptions(builder.kind) {
should_run = (desc.should_run)(should_run);
}
let mut help = String::from("Available paths:\n");
for path in should_run.paths {
@ -240,30 +301,12 @@ impl<'a> Builder<'a> {
stack: RefCell::new(Vec::new()),
};
let builder = &builder;
match builder.kind {
Kind::Build => check!(builder, paths, 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 => check!(builder, paths, check::Tidy, check::Bootstrap, check::Compiletest,
check::Crate, check::CrateLibrustc, check::Linkcheck, check::Cargotest,
check::Cargo, check::Docs, check::ErrorIndex, check::Distcheck),
Kind::Bench => check!(builder, paths, check::Crate, check::CrateLibrustc),
Kind::Doc => builder.default_doc(Some(paths)),
Kind::Dist => check!(builder, paths, 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 => check!(builder, paths, install::Docs, install::Std, install::Cargo,
install::Rls, install::Analysis, install::Src, install::Rustc),
}
StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths);
}
pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
let paths = paths.unwrap_or(&[]);
check!(self, paths, doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone,
doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, doc::Reference);
StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths);
}
/// Obtain a compiler at a given stage and for a given host. Explictly does
@ -514,43 +557,6 @@ impl<'a> Builder<'a> {
cargo
}
fn maybe_run<S: Step>(&self, path: Option<&Path>) {
let build = self.build;
let hosts = if S::ONLY_BUILD_TARGETS || S::ONLY_BUILD {
&build.config.host[..1]
} else {
&build.hosts
};
// Determine the actual targets participating in this rule.
// NOTE: We should keep the full projection from build triple to
// the hosts for the dist steps, now that the hosts array above is
// truncated to avoid duplication of work in that case. Therefore
// the original non-shadowed hosts array is used below.
let targets = if S::ONLY_HOSTS {
// If --target was specified but --host wasn't specified,
// don't run any host-only tests. Also, respect any `--host`
// overrides as done for `hosts`.
if build.flags.host.len() > 0 {
&build.flags.host[..]
} else if build.flags.target.len() > 0 {
&[]
} else if S::ONLY_BUILD {
&build.config.host[..1]
} else {
&build.config.host[..]
}
} else {
&build.targets
};
for host in hosts {
for target in targets {
S::make_run(self, path, *host, *target);
}
}
}
/// Ensure that a given step is built, returning it's output. This will
/// cache the step, so it is safe (and good!) to call this as often as
/// needed to ensure that all dependencies are built.