aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-04-02 15:06:55 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-04-02 15:06:55 +0200
commit65dca85d0acc1ae69518e85b52a2877e38dc8c6d (patch)
tree7e2f1c227d5114d30b8c84e2d9f6af826a36066a
parent48f8883de7b8fa348423b3baf262de08c98eba18 (diff)
Implement translation of meta/operations to natural language
-rw-r--r--build/algorithm.cxx30
-rw-r--r--build/config/operation.cxx6
-rw-r--r--build/diagnostics15
-rw-r--r--build/diagnostics.cxx99
-rw-r--r--build/operation18
-rw-r--r--build/operation.cxx38
-rw-r--r--build/rule.cxx4
7 files changed, 186 insertions, 24 deletions
diff --git a/build/algorithm.cxx b/build/algorithm.cxx
index 91ece49..d649210 100644
--- a/build/algorithm.cxx
+++ b/build/algorithm.cxx
@@ -73,11 +73,12 @@ namespace build
{
auto g (
make_exception_guard (
- [](target& t, const string& n)
+ [](action a, target& t, const string& n)
{
- info << "while matching rule " << n << " for target " << t;
+ info << "while matching rule " << n << " to "
+ << diag_do (a, t);
},
- t, n));
+ a, t, n));
m = ru.match (a, t, hint);
}
@@ -99,12 +100,12 @@ namespace build
{
auto g (
make_exception_guard (
- [](target& t, const string& n1)
+ [](action a, target& t, const string& n1)
{
- info << "while matching rule " << n1 << " for target "
- << t;
+ info << "while matching rule " << n1 << " to "
+ << diag_do (a, t);
},
- t, n1));
+ a, t, n1));
m1 = ru1.match (a, t, hint);
}
@@ -113,7 +114,7 @@ namespace build
{
if (!ambig)
{
- dr << fail << "multiple rules matching target " << t
+ dr << fail << "multiple rules matching " << diag_doing (a, t)
<< info << "rule " << n << " matches";
ambig = true;
}
@@ -126,11 +127,12 @@ namespace build
{
auto g (
make_exception_guard (
- [](target& t, const string& n)
+ [](action a, target& t, const string& n)
{
- info << "while applying rule " << n << " for target " << t;
+ info << "while applying rule " << n << " to "
+ << diag_do (a, t);
},
- t, n));
+ a, t, n));
t.recipe (a, ru.apply (a, t, m));
break;
@@ -142,7 +144,7 @@ namespace build
}
if (!t.recipe (a))
- fail << "no rule to update target " << t;
+ fail << "no rule to " << diag_do (a, t);
}
void
@@ -215,8 +217,8 @@ namespace build
auto g (
make_exception_guard (
- [](target& t){info << "while updating target " << t;},
- t));
+ [](action a, target& t){info << "while " << diag_doing (a, t);},
+ a, t));
ts = t.recipe (a) (a, t);
assert (ts != target_state::unknown && ts != target_state::failed);
diff --git a/build/config/operation.cxx b/build/config/operation.cxx
index 5b9cc5c..3269f9d 100644
--- a/build/config/operation.cxx
+++ b/build/config/operation.cxx
@@ -173,6 +173,9 @@ namespace build
meta_operation_info configure {
"configure",
+ "configure",
+ "configuring",
+ "configured",
nullptr, // meta-operation pre
&configure_operation_pre,
&load, // normal load
@@ -272,6 +275,9 @@ namespace build
meta_operation_info disfigure {
"disfigure",
+ "disfigure",
+ "disfiguring",
+ "disfigured",
nullptr, // meta-operation pre
&disfigure_operation_pre,
&disfigure_load,
diff --git a/build/diagnostics b/build/diagnostics
index 21e02e2..64a0107 100644
--- a/build/diagnostics
+++ b/build/diagnostics
@@ -36,6 +36,21 @@ namespace build
return os << diag_relative (p);
}
+ // Action phrases, e.g., "configure update exe{foo}", "updating exe{foo}",
+ // and "updating exe{foo} already configured".
+ //
+ struct action;
+ class target;
+
+ std::string
+ diag_do (const action&, const target&);
+
+ std::string
+ diag_doing (const action&, const target&);
+
+ std::string
+ diag_already_done (const action&, const target&);
+
// Print process commmand line.
//
void
diff --git a/build/diagnostics.cxx b/build/diagnostics.cxx
index 43ee0e5..aab7675 100644
--- a/build/diagnostics.cxx
+++ b/build/diagnostics.cxx
@@ -4,8 +4,12 @@
#include <build/diagnostics>
+#include <sstream>
#include <iostream>
+#include <build/scope>
+#include <build/target>
+#include <build/operation>
#include <build/context>
#include <build/utility>
@@ -53,6 +57,101 @@ namespace build
return p.string ();
}
+ // diag_do(), etc.
+ //
+ string
+ diag_do (const action& a, const target& t)
+ {
+ // @@ root scope
+ //
+ scope& root (
+ scopes.find (
+ scopes.find (t.dir)["out_root"].as<const path&> ()));
+
+ const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]);
+ const operation_info& oi (root.operations[a.operation ()]);
+
+ ostringstream os;
+
+ // perform(update(x)) -> "update x"
+ // configure(update(x)) -> "configure updating x"
+ //
+ if (mi.name_do.empty ())
+ os << oi.name_do << ' ';
+ else
+ {
+ os << mi.name_do << ' ';
+
+ if (!oi.name_doing.empty ())
+ os << oi.name_doing << ' ';
+ }
+
+ os << t;
+ return os.str ();
+ }
+
+ string
+ diag_doing (const action& a, const target& t)
+ {
+ // @@ root scope
+ //
+ scope& root (
+ scopes.find (
+ scopes.find (t.dir)["out_root"].as<const path&> ()));
+
+ const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]);
+ const operation_info& oi (root.operations[a.operation ()]);
+
+ ostringstream os;
+
+ // perform(update(x)) -> "updating x"
+ // configure(update(x)) -> "configuring updating x"
+ //
+ if (!mi.name_doing.empty ())
+ os << mi.name_doing << ' ';
+
+ if (!oi.name_doing.empty ())
+ os << oi.name_doing << ' ';
+
+ os << t;
+ return os.str ();
+ }
+
+ string
+ diag_already_done (const action& a, const target& t)
+ {
+ // @@ root scope
+ //
+ scope& root (
+ scopes.find (
+ scopes.find (t.dir)["out_root"].as<const path&> ()));
+
+ const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]);
+ const operation_info& oi (root.operations[a.operation ()]);
+
+ ostringstream os;
+
+ // perform(update(x)) -> "x is already up to date"
+ // configure(update(x)) -> "updating x is already configured"
+ //
+ if (mi.name_already_done.empty ())
+ {
+ os << t;
+
+ if (!oi.name_already_done.empty ())
+ os << " is already " << oi.name_already_done;
+ }
+ else
+ {
+ if (!oi.name_doing.empty ())
+ os << oi.name_doing << ' ';
+
+ os << t << " is already " << mi.name_already_done;
+ }
+
+ return os.str ();
+ }
+
void
print_process (const char* const* args)
{
diff --git a/build/operation b/build/operation
index ac93999..3d9c4a4 100644
--- a/build/operation
+++ b/build/operation
@@ -122,6 +122,13 @@ namespace build
{
const std::string name;
+ // Name derivatives for diagnostics. If empty, then the meta-
+ // operation need not be mentioned.
+ //
+ const std::string name_do; // E.g., [to] 'configure'.
+ const std::string name_doing; // E.g., [while] 'configuring'.
+ const std::string name_already_done; // E.g., [already] 'configured'.
+
void (*meta_operation_pre) (); // Start of meta-operation batch.
operation_id (*operation_pre) (operation_id); // Start of operation batch.
@@ -184,6 +191,17 @@ namespace build
struct operation_info
{
const std::string name;
+
+ // Name derivatives for diagnostics. Note that unlike meta-operations,
+ // these can only be empty for the default operation (id 1), And
+ // meta-operations that make use of the default operation shall not
+ // have empty derivatives (failed which only target name will be
+ // printed).
+ //
+ const std::string name_do; // E.g., [to] 'update'.
+ const std::string name_doing; // E.g., [while] 'updating'.
+ const std::string name_already_done; // E.g., [already] 'up to date'.
+
const execution_mode mode;
};
diff --git a/build/operation.cxx b/build/operation.cxx
index 7fab63e..0d6bfcd 100644
--- a/build/operation.cxx
+++ b/build/operation.cxx
@@ -98,19 +98,19 @@ namespace build
{
target& t (*static_cast<target*> (v));
- level4 ([&]{trace << "executing target " << t;});
+ level4 ([&]{trace << diag_doing (a, t);});
switch (execute (a, t))
{
case target_state::postponed:
{
- info << "target " << t << " is postponed";
+ info << diag_doing (a, t) << " is postponed";
psp.push_back (t);
break;
}
case target_state::unchanged:
{
- info << "target " << t << " is unchanged";
+ info << diag_already_done (a, t);
break;
}
case target_state::changed:
@@ -130,12 +130,12 @@ namespace build
{
case target_state::postponed:
{
- info << "unable to execute target " << t << " at this time";
+ info << "unable to " << diag_do (a, t) << " at this time";
break;
}
case target_state::unchanged:
{
- info << "target " << t << " is unchanged";
+ info << diag_already_done (a, t);
break;
}
case target_state::unknown: // Assume something was done to it.
@@ -151,6 +151,9 @@ namespace build
meta_operation_info perform {
"perform",
+ "",
+ "",
+ "",
nullptr, // meta-operation pre
nullptr, // operation pre
&load,
@@ -162,7 +165,26 @@ namespace build
// operations
//
- operation_info default_ {"<default>", execution_mode::first};
- operation_info update {"update", execution_mode::first};
- operation_info clean {"clean", execution_mode::last};
+ operation_info default_ {
+ "<default>",
+ "",
+ "",
+ "",
+ execution_mode::first
+ };
+
+ operation_info update {
+ "update",
+ "update",
+ "updating",
+ "up to date",
+ execution_mode::first
+ };
+
+ operation_info clean {
+ "clean",
+ "clean",
+ "cleaning",
+ "clean",
+ execution_mode::last};
}
diff --git a/build/rule.cxx b/build/rule.cxx
index fb5af3f..413676b 100644
--- a/build/rule.cxx
+++ b/build/rule.cxx
@@ -125,7 +125,7 @@ namespace build
timestamp mp (mpt->mtime ());
if (mt < mp)
- fail << "no recipe to update target " << t <<
+ fail << "no recipe to " << diag_do (a, t) <<
info << "prerequisite " << pt << " is ahead of " << t
<< " by " << (mp - mt);
}
@@ -134,7 +134,7 @@ namespace build
// Otherwise we assume the prerequisite is newer if it was changed.
//
if (ts == target_state::changed)
- fail << "no recipe to update target " << t <<
+ fail << "no recipe to " << diag_do (a, t) <<
info << "prerequisite " << pt << " is ahead of " << t
<< " because it was updated";
}