aboutsummaryrefslogtreecommitdiff
path: root/libbbot/build-config.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbbot/build-config.cxx')
-rw-r--r--libbbot/build-config.cxx109
1 files changed, 96 insertions, 13 deletions
diff --git a/libbbot/build-config.cxx b/libbbot/build-config.cxx
index de9a71d..2e6dfbc 100644
--- a/libbbot/build-config.cxx
+++ b/libbbot/build-config.cxx
@@ -4,9 +4,10 @@
#include <libbbot/build-config.hxx>
+#include <map>
#include <string>
#include <cstddef> // size_t
-#include <utility> // move()
+#include <utility> // move(), make_pair()
#include <stdexcept> // invalid_argument
#include <libbutl/path.mxx>
@@ -56,6 +57,14 @@ namespace bbot
build_config config;
config.machine_pattern = move (tl[i++].value);
+ // If the machine pattern is a single dash character, then this is a
+ // placeholder entry. The only thing we are interested about it is the
+ // class inheritance information. Note that while all other information
+ // is discarded, the configuration name and target must be present (can
+ // also be dashes), so the classes field can be determined and parsed.
+ //
+ bool placeholder (config.machine_pattern == "-");
+
// Configuration name, target and classes fields are the required ones.
//
if (i == n)
@@ -74,6 +83,7 @@ namespace bbot
if (++i == n)
bad_line ("no target found");
+ if (!placeholder)
try
{
config.target = target_triplet (tl[i].value);
@@ -90,21 +100,75 @@ namespace bbot
//
try
{
- // We don't expect the class names be quotes as they cannot contain
- // spaces.
- //
using namespace string_parser;
- config.classes = parse_quoted (unquote (tl[i].value),
- false /* unquote */);
- // Validate the class names.
- //
- for (const string& c: config.classes)
+ auto validate = [] (const string& c)
{
+ bpkg::build_class_term::validate_name (c);
+
if (c == "none")
throw invalid_argument ("class 'none' is reserved");
+ };
- bpkg::build_class_term::validate_name (c);
+ // We don't expect the class names be quotes as they cannot contain
+ // spaces.
+ //
+ for (string& c: parse_quoted (unquote (tl[i].value),
+ false /* unquote */))
+ {
+ string base;
+ size_t p (c.find (':'));
+
+ if (p != string::npos)
+ {
+ base = string (c, p + 1);
+ validate (base);
+
+ c.resize (p);
+ }
+
+ validate (c);
+
+ // Add the mapping of the derived class to its base.
+ //
+ // Note that it's not required for a base to also be registered in
+ // the map.
+ //
+ auto i (r.class_inheritance_map.insert (make_pair (c, base)));
+
+ // If the derived-to-base mapping is added, then verify that there
+ // is no inheritance cycle. Otherwise, verify that the base class is
+ // the same as for the existing mapping. Note that once the base
+ // class is specified it can be omitted for subsequent mentions of
+ // the derived class.
+ //
+ auto j (i.first);
+
+ if (i.second) // Added?
+ {
+ // Traverse through the class hierarchy up until a non-registered
+ // base (in particular an empty one) is encountered.
+ //
+ // Note: here we also handle the 'base of itself' case.
+ //
+ while (j != r.class_inheritance_map.end ())
+ {
+ const string& base (j->second);
+
+ if (base == c)
+ throw invalid_argument (
+ "inheritance cycle in '" + c + "' class inheritance");
+
+ j = r.class_inheritance_map.find (base);
+ }
+ }
+ else if (j->second != base && !base.empty ())
+ throw invalid_argument ("'" + c + "' new base '" + base +
+ "' does not match existing '" +
+ j->second + "'");
+
+ if (!placeholder)
+ config.classes.emplace_back (move (c));
}
}
catch (const invalid_argument& e)
@@ -112,6 +176,13 @@ namespace bbot
bad_line (e.what ());
}
+ // We are done if this is a placeholder.
+ //
+ if (placeholder)
+ continue;
+
+ // Parse options, variables, and regexes.
+ //
try
{
for (++i; i < n; ++i)
@@ -121,11 +192,11 @@ namespace bbot
if (v[0] == '~') // Regular expression.
{
string re (v, 1);
- task_manifest::check_regex (re);
+ task_manifest::validate_regex (re);
config.warning_regexes.emplace_back (move (re));
}
- else // Configuration variable.
- config.vars.emplace_back (move (v));
+ else // Configuration option or variable.
+ config.args.emplace_back (move (v));
}
}
catch (const invalid_argument& e)
@@ -138,6 +209,18 @@ namespace bbot
r.emplace_back (move (config));
}
+ // Erase entries for baseless classes (we were collecting them to make
+ // sure that the class inheritance is consistent across configurations).
+ //
+ for (auto i (r.class_inheritance_map.begin ());
+ i != r.class_inheritance_map.end (); )
+ {
+ if (i->second.empty ())
+ i = r.class_inheritance_map.erase (i);
+ else
+ ++i;
+ }
+
return r;
}