Change:
introduced some checks which execute 4 times. They run unconditionally when executing , even if it is just to run tidy. On my system the wall time exceeds that of running tidy itself. I'll look into whether the checks themselves can be made be less wasteful. But if there are suggestions how to completely eliminate them or defer them while preserving their original purpose that would be great too. ! CC can you explain the purpose of running this in rather than erroring in ?
To know beforehand if the test should unconditionally be run or not. If the test is run and the npm package isn't installed, we panic. To be noted that we could make it go down to 2 by switching the order of : currently we check both "local" and "global". Switching the two of them will divide the number of calls by two. cc
I don't have installed, so it'll fail and no short-circuiting will happen regardless of order.
In case you don't have it it'll check 4 times indeed.
Hm, this does seem annoying. It's possible we could add some lazily-evaluated default condition so that this never runs if we're not considering default-on steps (if defaults are on, then these npm lists are likely quite fast in comparison to the rest of the logic).

Discussion:
"libc", "merge", "num_cpus", <ins> "once_cell", </ins> "opener", "pretty_assertions", "serde",

ignore = "0.4.10" opener = "0.4" merge = "0.1.0" <ins> once_cell = "1.7.2" </ins> [target.'cfg(windows)'.dependencies.winapi] version = "0.3"

use crate::{Build, DocTests, GitRepo, Mode}; pub use crate::Compiler; <ins> // FIXME: replace with std::lazy after it gets stabilized and reaches beta use once_cell::sync::Lazy; </ins> pub struct Builder<'a> { pub build: &'a Build,

if paths.is_empty() || builder.config.include_default_paths { for (desc, should_run) in v.iter().zip(&should_runs) { <del> if desc.default && should_run.is_really_default { </del> <ins> if desc.default && should_run.is_really_default() { </ins> for pathset in &should_run.paths { desc.maybe_run(builder, pathset); }

} } <del> #[derive(Clone)] </del> <ins> enum ReallyDefault<'a> { Bool(bool), Lazy(Lazy<bool, Box<dyn Fn() -> bool + 'a>>), } </ins> pub struct ShouldRun<'a> { pub builder: &'a Builder<'a>, // use a BTreeSet to maintain sort order

// If this is a default rule, this is an additional constraint placed on // its run. Generally something like compiler docs being enabled. <del> is_really_default: bool, </del> <ins> is_really_default: ReallyDefault<'a>, </ins> } impl<'a> ShouldRun<'a> {

ShouldRun { builder, paths: BTreeSet::new(), <del> is_really_default: true, // by default no additional conditions </del> <ins> is_really_default: ReallyDefault::Bool(true), // by default no additional conditions </ins> } } pub fn default_condition(mut self, cond: bool) -> Self { <del> self.is_really_default = cond; </del> <ins> self.is_really_default = ReallyDefault::Bool(cond); self } pub fn lazy_default_condition(mut self, lazy_cond: Box<dyn Fn() -> bool + 'a>) -> Self { self.is_really_default = ReallyDefault::Lazy(Lazy::new(lazy_cond)); </ins> self } <ins> pub fn is_really_default(&self) -> bool { match &self.is_really_default { ReallyDefault::Bool(val) => *val, ReallyDefault::Lazy(lazy) => *lazy.deref(), } } </ins> /// Indicates it should run if the command-line selects the given crate or /// any of its (local) dependencies. ///

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; let run = run.suite_path("src/test/rustdoc-gui"); <del> run.default_condition( </del> <ins> run.lazy_default_condition(Box::new(move || { </ins> builder.config.nodejs.is_some() && builder .config .npm .as_ref() .map(|p| check_if_browser_ui_test_is_installed(p)) <del> .unwrap_or(false), ) </del> <ins> .unwrap_or(false) })) </ins> } fn make_run(run: RunConfig<'_>) {