aboutsummaryrefslogtreecommitdiff
path: root/build2/test
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-02-07 10:00:46 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-02-07 14:05:39 +0200
commit378b2598a305d4e332e52460ca89dd867546a58b (patch)
tree7541771843232bc6d51880d58a57e25737b7ba13 /build2/test
parentf10be65c39c18668df31c8680569a6417ef3ae06 (diff)
Initial work for default update outer operation
While update still uses the old "all update rules update all their prerequisites" assumption, test and install have been fixed not to rely on this.
Diffstat (limited to 'build2/test')
-rw-r--r--build2/test/rule.cxx83
-rw-r--r--build2/test/rule.hxx2
2 files changed, 57 insertions, 28 deletions
diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx
index 7c55445..86062f9 100644
--- a/build2/test/rule.cxx
+++ b/build2/test/rule.cxx
@@ -142,16 +142,32 @@ namespace build2
break;
}
- // If this is the test operation, collect testscripts after the
- // pass-through prerequisites.
+ // Collect testscripts after the pass-through prerequisites.
//
- // Note that we don't match nor execute them relying on update to
- // assign their paths and make sure they are up to date.
+ const target& pt (p.search (t));
+
+ // Note that for the test operation itself we don't match nor
+ // execute them relying on update to assign their paths.
+ //
+ // Causing update for test inputs/scripts is tricky: we cannot
+ // match for update_for_install because this same rule will match
+ // and since the target is not testable, it will return the noop
+ // recipe.
+ //
+ // So what we are going to do is directly match (and also execute;
+ // see below) a recipe for the inner update (who thought we could
+ // do that... but it seems we can). While at first it might feel
+ // iffy, it does make sense: the outer rule we would have matched
+ // would have simply delegated to the inner so we might as well
+ // take a shortcut. The only potential drawback of this approach
+ // is that we won't be able to provide any for_test customizations
+ // when updating test inputs/scripts. But such a need seems rather
+ // far fetched.
//
- if (a.operation () != test_id)
- break;
+ if (a.operation () == update_id)
+ match_inner (a, pt);
- pts.push_back (&p.search (t));
+ pts.push_back (&pt);
}
}
@@ -196,14 +212,9 @@ namespace build2
if (si || so || in)
{
- // Note that we don't match nor execute them relying on update
- // to assign their paths and make sure they are up to date.
- //
- const target& pt (p.search (t));
-
// Verify it is file-based.
//
- if (!pt.is_a<file> ())
+ if (!p.is_a<file> ())
{
fail << "test." << (si ? "stdin" : so ? "stdout" : "input")
<< " prerequisite " << p << " of target " << t
@@ -214,9 +225,6 @@ namespace build2
{
test = true;
- if (a.operation () != test_id)
- break;
-
// First matching prerequisite. Establish the structure in
// pts: the first element (after pass_n) is stdin (can be
// NULL), the second is stdout (can be NULL), and everything
@@ -226,13 +234,31 @@ namespace build2
pts.push_back (nullptr); // stdout
}
+ // Collect them after the pass-through prerequisites.
+ //
+ // Note that for the test operation itself we don't match nor
+ // execute them relying on update to assign their paths.
+ //
+ auto match = [a, &p, &t] () -> const target*
+ {
+ const target& pt (p.search (t));
+
+ // The same match_inner() rationale as for the testcript
+ // prerequisites above.
+ //
+ if (a.operation () == update_id)
+ match_inner (a, pt);
+
+ return &pt;
+ };
+
if (si)
{
if (pts[pass_n] != nullptr)
fail << "multiple test.stdin prerequisites for target "
<< t;
- pts[pass_n] = &pt;
+ pts[pass_n] = match ();
}
if (so)
@@ -241,11 +267,11 @@ namespace build2
fail << "multiple test.stdout prerequisites for target "
<< t;
- pts[pass_n + 1] = &pt;
+ pts[pass_n + 1] = match ();
}
if (in)
- pts.push_back (&pt);
+ pts.push_back (match ());
}
}
@@ -274,11 +300,13 @@ namespace build2
if (a.operation () == update_id)
{
// For the update pre-operation match the inner rule (actual update).
- // Note that here we assume it will update (if required) all the
- // testscript and input/output prerequisites.
//
match_inner (a, t);
- return &perform_update;
+
+ return [pass_n, this] (action a, const target& t)
+ {
+ return perform_update (a, t, pass_n);
+ };
}
else
{
@@ -300,15 +328,16 @@ namespace build2
}
target_state rule::
- perform_update (action a, const target& t)
+ perform_update (action a, const target& t, size_t pass_n)
{
- // First execute the inner recipe, then, if passing-through, execute
- // prerequisites.
+ // First execute the inner recipe then execute prerequisites.
//
target_state ts (execute_inner (a, t));
- if (t.prerequisite_targets[a].size () != 0)
- ts |= straight_execute_prerequisites (a, t);
+ if (pass_n != 0)
+ ts |= straight_execute_prerequisites (a, t, pass_n);
+
+ ts |= straight_execute_prerequisites_inner (a, t, 0, pass_n);
return ts;
}
diff --git a/build2/test/rule.hxx b/build2/test/rule.hxx
index 4f02390..85fa1cd 100644
--- a/build2/test/rule.hxx
+++ b/build2/test/rule.hxx
@@ -27,7 +27,7 @@ namespace build2
apply (action, target&) const override;
static target_state
- perform_update (action, const target&);
+ perform_update (action, const target&, size_t);
target_state
perform_test (action, const target&, size_t) const;